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

时间:2019-09-05 09:33:58

标签: android in-app-purchase

我在弄清楚如何使用com.android.billingclient:billing:2.0.3检测何时为Android中的托管(非消耗性)应用程序内产品退款时遇到了麻烦。这个问题似乎很严重,尽管我可能使它变得比应有的复杂。

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

enter image description here

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

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

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

  1. 我们可以看到图像中的商品和检测到的购买商品之间的订单ID相匹配
  2. 第一行日志是使用Log.d(TAG, "Got a verified purchase: " + purchase);打印购买,这将打印表示purchase的基础JSON。
  3. 请注意,"purchaseState":0
  4. 第二条日志行带有Log.i(TAG, "purchase " + purchase.getPurchaseToken() + " is in " + purchase.getPurchaseState() + " state");
  5. 请注意,此处purchase.getPurchaseState()的值为1

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

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

在文件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;
  }

似乎getPurchaseState从不返回PurchaseState.UNSPECIFIED_STATE,而仅返回PENDING,JSON带有4值。我已经确认,使用需要一段时间才能批准的付款方式进行购买时,正确返回了PENDING状态。

我找到了类似In-App Billing v3 - Don't detect refund的帖子,这些帖子暗示Play服务正在缓存购买的商品,但我不相信这是导致此问题的原因,因为如果我修改应用运行之间的代码以确认/消费这些商品,获取状态更改会立即反映在购买的JSON中。

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

2 个答案:

答案 0 :(得分:1)

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

 binding.btnRestore.setOnClickListener(v->{


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

            }
});

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

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

        }

    }

答案 1 :(得分:1)

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

问题:

purchase.getOriginalJson()  // contains "purchaseState":0
purchase.getPurchaseState() // returns 1

在com.android.billingclient.api。内部:

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;
}

从原始json检查purchaseState的简便方法:

purchase.getOriginalJson().contains(String.format("\"purchaseState\":%s", Purchase.PurchaseState.PURCHASED))