Android Google BillingClient如何获取未消费的物品?

时间:2018-07-10 12:02:02

标签: android in-app-purchase in-app-billing android-inapp-purchase

问题:使用Google Play BillingClient 1.1如何只能获得未消费的购买?

背景

在我们的Android应用中,我们希望使用新的“旧的”计费库(使用示例中的V.3 IabHelper.java类)

com.android.billingclient:billing:1.1

想法是使用

BillingClient.queryPurchases(BillingClient.SkuType.INAPP)

,以便获得用户进行的所有购买的“历史记录”。这就是API告诉(https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#queryPurchases(java.lang.String))的内容,并且可以正常工作。 在旧版本中,只会得到未消费的物品,这对于诸如“ 购买历史”之类的东西是无用的。但是,如果我想知道是否有未消费的物品,我将无法再获取该信息。

queryPurchaseHistoryAsync()相同。

“购买”对象似乎不包含有关其消费的任何信息。 如何仅获取未消费的物品(或至少将其过滤)?

请注意,我知道最终必须在我们的服务器端管理购买。但是,在成功完成之前,最好先知道哪个项目已“赎回”(消耗)(已消耗)。所以我不能只依靠我们的后端。

----编辑----

来自查询的购买对象(JSON)都看起来像这样:

{
  "orderId": "[Id]",
  "packageName": "[just the app's package]",
  "productId": "[the SKU name]",
  "purchaseTime": 1531224460215,
  "purchaseState": 0,
  "purchaseToken": "[a purchase token]"
}

所以似乎没有什么是消耗状态。

----编辑2 ----

我找到了一个(不好的)解决方案。尝试消费时,Google会通过返回码告诉我是否已经消费过。但这对我们来说不是解决方案,因为我们希望在将其“标记为未消费”到服务器上之前将其“标记为未消费”。

3 个答案:

答案 0 :(得分:2)

好的,我想我找到了答案。如果您遇到与我相同的问题,请使用以下解决方案:

billingClient有两个方法调用。

  • 第一个是

billingClient.queryPurchaseHistoryAsync()

此异步调用(需要互联网)正在获取用户最近11次购买的历史记录。最新的是第一个(列表中的元素0)。 但是,这显示了所有购买-无论是否消费。因此,如果您想知道他们的状态,就不能在这里进行。 如果您具有后端系统(并且网络连接正常),则可以将它们全部发送到服务器并进行验证。由于我们的应用程序是“离线优先”的应用,因此我们的用户并非总是可以做到这一点。

但是,当您尝试再次购买它们时,可以检查此内容。调用billingClient.launchBillingFlow()会返回responseCode ITEM_ALREADY_OWNED(7),但您不想等待用户尝试再次购买它。特别是因为我们希望即使没有互联网连接也能保证购买。

  • 解决方法是另一种方法。

BillingClient提供:

billingClient.queryPurchases(BillingClient.SkuType.INAPP)

这将返回已缓存的先前购买的列表。 The API将此声明为

  

获取您在应用内购买的所有商品的购买明细。

但是,这似乎只返回未消费项目的列表。这样,您可以从所有(最近的)购买清单中获得未消费的物品。但是请注意,这是由Playstore缓存的。如果您需要确切的数据,则仍然必须与Google服务器建立连接(同样在清除Playstore缓存等时也是如此)。

这提供了所有购买历史记录的选项,其中包含有关未消费物品的附加信息,这使您的应用程序(部分)可以离线使用。

至少这是我想出的最好方法,但似乎可行。 请让我知道您是否有任何更正或更好的解决方案!!!

答案 1 :(得分:1)

官方文档说,建议您通过https://developers.google.com/android-publisher/api-ref/purchases/products/get请求检查购买情况。在JSON响应中,有一个consumptionState字段,显示是否消费了购买的商品。

{
  "kind": "androidpublisher#productPurchase",
  "purchaseTimeMillis": long,
  "purchaseState": integer,
  "consumptionState": integer,
  "developerPayload": string,
  "orderId": string,
  "purchaseType": integer
}

了解更多信息https://developers.google.com/android-publisher/api-ref/purchases/products#resource。 这样,您可以使用queryPurchaseHistoryAsync网络查询来接收购买并如上所述进行检查。但是这种方法并不容易,因为请求需要授权,需要对其进行配置https://developers.google.com/android-publisher/authorization

答案 2 :(得分:0)

            // When you call consumeAsync(),you shoud set developerPayload to distinguish consumed purchases.
            ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchaseToken).setDeveloperPayload("userid_time_consumed").build();
            mBillingClient.consumeAsync(consumeParams, new ConsumeResponseListener() {
                @Override
                public void onConsumeResponse(BillingResult result, String purchaseToken) {
                    if (result.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                        //do something
                    } else {
                        String errorMsg = "Recovery consume failed: " + result.getDebugMessage() + " Response code:" + result.getResponseCode();
                        Log.e(TAG, errorMsg);
                        //do something
                    }
                }
            });
        mBillingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.INAPP, new PurchaseHistoryResponseListener() {
            @Override
            public void onPurchaseHistoryResponse(BillingResult result, List<PurchaseHistoryRecord> purchaseHistoryRecords) {
                if (mBillingClient == null) {
                    String errorMsg = "Store recovery failed, mBillingClient is null.";
                    Log.e(TAG, errorMsg);
                    return;
                }

                if (result.getResponseCode() != BillingClient.BillingResponseCode.OK) {
                    String errorMsg = "Query purchase history failed. " + result.getResponseCode();
                    Log.e(TAG, errorMsg);
                    return;
                }

                if (purchaseHistoryRecords != null && purchaseHistoryRecords.size() > 0) {
                    for (PurchaseHistoryRecord purchase : purchaseHistoryRecords) {
                        // Purchases need to be repaid only if payload is empty, which indicates failed to notify app server.
                        String payload = purchase.getDeveloperPayload();
                        if (payload == null || "null".equalsIgnoreCase(payload) || payload.isEmpty()) {
                            //notify app server ,when get the result "OK" from app server ,you should call consumeAsync(). (ps:you also need to set the "developerPayload")
                        }
                    }
                } else {
                    Log.d(TAG, "Purchase history is empty.");
                }
            }
        });