5

问题:使用 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 ----

我找到了一个(坏的)解决方案。当尝试消费购买时,谷歌告诉我它的返回码是否已经被消费。但这不是我们的解决方案,因为我们希望将其“标记为未使用”,直到它在我们的服务器上被赎回。

4

3 回答 3

5

好吧,我想我找到了答案。如果你和我有同样的问题,这里是解决方案:

billingClient 有两个方法调用。

  • 第一个是

billingClient.queryPurchaseHistoryAsync().

此异步调用(需要 Internet)正在获取用户最近 11 次购买的历史记录。最新的是第一个(列表的元素 0)。然而,这显示了所有购买 - 无论它们是否被消费。所以如果你想知道他们的状态,你不能在这里做。如果您有一个后端系统(和一个有效的网络连接),您可以将它们全部发送到服务器并验证它们。由于我们的应用是“离线优先”的,这对我们的用户来说并不总是可行的。

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

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

BillingClient 提供:

billingClient.queryPurchases(BillingClient.SkuType.INAPP)

这将返回以前购买的缓存列表。API 将其声明为

获取在您的应用内购买的所有商品的购买详情。

然而,这似乎只返回了一个未消费项目的列表。通过这种方式,您可以从所有(最近)购买的列表中获取未消耗的物品。但是请注意,这是由 playstore 缓存的。如果您需要确切的数据,您仍然需要与 google 服务器建立连接(在清除 playstore 缓存时等)。

这提供了所有购买历史的选项以及有关未消费项目的附加信息,这使您的应用程序(部分)离线可用。

至少这是我想出的最好的方法,但它似乎有效。如果您有任何更正或更好的解决方案,请告诉我!!!

于 2018-07-12T10:13:28.593 回答
2

官方文档说建议使用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

于 2018-12-19T06:46:58.373 回答
1
            // 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.");
                }
            }
        });
于 2020-07-03T10:45:05.417 回答