检测退款的托管应用内购买 android IAP 2.0.3

Pay*_*ian 10 android in-app-purchase

我无法弄清楚如何使用com.android.billingclient:billing:2.0.3. 这个问题似乎相当深,但也许我让它变得比它应该的更复杂。

首先,我进行了一次已确认并退款的测试购买:

在此处输入图片说明

查看我的应用程序的日志,我看到以下内容:

D/BillingManager: Got a verified purchase: Purchase. Json: {"orderId":"GPA.3362-7185-5389-78416","packageName":"com.glan.input","productId":"pro","purchaseTime":1567672759460,"purchaseState":0,"purchaseToken":"pbkpcaadklleoecegjfjdpbl.AO-J1OwsR6WVaVZCCYOU6JyYN1r0qJsrwitIPZfhc3jX4yketRUwNzKqwMgYx0TgZ2GebEGbXDL0RlMyogwtSKSPsaHCJ4RA4MPlIGay-aM1-QhmnqwjXjQ","acknowledged":true}
I/BillingManager: purchase pbkpcaadklleoecegjfjdpbl.AO-J1OwsR6WVaVZCCYOU6JyYN1r0qJsrwitIPZfhc3jX4yketRUwNzKqwMgYx0TgZ2GebEGbXDL0RlMyogwtSKSPsaHCJ4RA4MPlIGay-aM1-QhmnqwjXjQ is in 1 state
Run Code Online (Sandbox Code Playgroud)

这里发生了一些有趣的事情:

  1. 我们可以看到图像中的内容与检测到的购买之间的订单 ID 匹配
  2. 第一个日志行是打印购买,Log.d(TAG, "Got a verified purchase: " + purchase);它打印代表purchase.
  3. 注意 "purchaseState":0
  4. 第二个日志行以Log.i(TAG, "purchase " + purchase.getPurchaseToken() + " is in " + purchase.getPurchaseState() + " state");.
  5. 请注意,这里purchase.getPurchaseState()产生的值为1

如果我查看getPurchaseStateAndroid Studio中的实现,我会看到以下内容:

  public @PurchaseState int getPurchaseState() {
    switch (mParsedJson.optInt("purchaseState", PurchaseState.PURCHASED)) {
      case 4:
        return PurchaseState.PENDING;
      default:
        return PurchaseState.PURCHASED;
    }
  }
Run Code Online (Sandbox Code Playgroud)

在文件的前面,PurchaseState接口被声明为:

  @Retention(SOURCE)
  public @interface PurchaseState {
    // Purchase with unknown state.
    int UNSPECIFIED_STATE = 0;
    // Purchase is completed.
    int PURCHASED = 1;
    // Purchase is waiting for payment completion.
    int PENDING = 2;
  }
Run Code Online (Sandbox Code Playgroud)

似乎getPurchaseState永远不会返回PurchaseState.UNSPECIFIED_STATE并且只返回PENDINGJSON 带有值的4. 我已经确认,PENDING当使用需要一段时间才能批准的付款方式进行购买时,状态会正确返回。

我发现了诸如应用内结算 v3 - 未检测到表明 Play 服务正在缓存购买的退款之类的帖子,但我不相信这是导致此问题的原因,因为如果我在应用程序运行之间修改我的代码以确认/使用购买状态更改会立即反映在购买的 JSON 中。

我应该如何检测退款的被管理产品?

kit*_*st0 8

我的应用程序中有一项购买 (SkuType.INAPP)。我进行测试购买,然后退款。

问题:

purchase.getOriginalJson()  // contains "purchaseState":0
purchase.getPurchaseState() // returns 1
Run Code Online (Sandbox Code Playgroud)

com.android.billingclient.api.Purchase 内部:

public int getPurchaseState() {
    switch(this.zzc.optInt("purchaseState", 1)) {
    case 4:
        return 2;
    default:
        return 1;
    }
}
//...
public @interface PurchaseState {
    int UNSPECIFIED_STATE = 0;
    int PURCHASED = 1;
    int PENDING = 2;
}
Run Code Online (Sandbox Code Playgroud)

从原始 json 检查purchaseState的hacky方法:

purchase.getOriginalJson().contains(String.format("\"purchaseState\":%s", Purchase.PurchaseState.PURCHASED))
Run Code Online (Sandbox Code Playgroud)

不幸的是,这个问题仍然存在!

更多详细信息请参见此处

  • 好的,这可行,但是当我在退款后尝试再次购买 INAPP 时,它会向我抛出“无法购买商品,错误响应代码:7”,该代码适用于已拥有的商品。 (3认同)

Bey*_*yaz 2

您可以检查是否仍购买退出以下

 binding.btnRestore.setOnClickListener(v->{


            Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
            for ( Purchase purchase : purchasesResult.getPurchasesList()){
                handlePurchase(purchase);

            }
});
Run Code Online (Sandbox Code Playgroud)

Google Play 返回登录设备的用户帐户进行的购买。如果请求成功,Play Billing Library 将查询结果存储在购买对象列表中。

注意:此列表中仅显示活动订阅。只要应用内产品在此列表中,用户就应该有权访问它。有关详细信息,请参阅添加特定于订阅的功能的处理 SUBSCRPTION_ON_HOLD 部分。要检索列表,请对PurchasesResult 调用getPurchasesList()。然后,您可以调用 Purchasing 对象上的各种方法来查看有关该商品的相关信息,例如其购买状态或时间。要查看可用的产品详细信息类型,请参阅Purchase 类中的方法列表。

您应该在代码中至少调用 queryPurchases() 两次:

每次应用程序启动时调用 queryPurchases() ,以便您可以恢复自应用程序上次停止以来用户进行的任何购买。在 onResume() 方法中调用 queryPurchases(),因为用户可以在您的应用程序处于后台时进行购买(例如,在 Google Play 商店应用程序中兑换促销代码)。在启动和恢复时调用 queryPurchases() 可以保证您的应用程序找出用户在应用程序未运行时可能进行的所有购买和兑换。此外,如果用户在应用程序运行时进行购买,而您的应用程序因任何原因错过了该购买,您的应用程序仍会在下次活动恢复时发现该购买并调用 queryPurchases()。

查询最近的购买 queryPurchases() 方法使用 Google Play 商店应用程序的缓存,无需发起网络请求。如果您需要检查用户对每个产品 ID 的最近购买记录,可以使用 queryPurchaseHistoryAsync(),传递购买类型和一个 PurchaseHistoryResponseListener 来处理查询结果。

queryPurchaseHistoryAsync() 返回一个 PurchaseHistory 对象,其中包含有关用户对每个产品 ID 进行的最近购买的信息,即使该购买已过期、取消或消耗。尽可能使用 queryPurchases(),因为它使用本地缓存,而不是 queryPurchaseHistoryAsync()。如果使用 queryPurchaseHistoryAsync(),您还可以将其与刷新按钮结合使用,从而允许用户更新其购买列表。

以下代码演示了如何重写 onPurchaseHistoryResponse() 方法:

  private void handlePurchase(Purchase purchase) {
        if(purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {

            if (purchase.getSku().equals(skuPro)) {
                EntityPRO entityPRO = RoomDB.getDatabase(context).proDAO().getLastItem();
                entityPRO.isBought = true;
                RoomDB.getDatabase(context).proDAO().updateSpecificSLI(entityPRO);
                Toast.makeText(context, context.getString(R.string.pro_succesfully_bought), Toast.LENGTH_LONG).show();

            }

            if (!purchase.isAcknowledged()) {
                AcknowledgePurchaseParams acknowledgePurchaseParams =
                        AcknowledgePurchaseParams.newBuilder()
                                .setPurchaseToken(purchase.getPurchaseToken())
                                .build();
                mBillingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
            }

        }

    }
Run Code Online (Sandbox Code Playgroud)