【问题标题】:Android Google BillingClient how to get unconsumed items?Android Google BillingClient 如何获取未消费的物品?
【发布时间】:2018-12-18 06:23:40
【问题描述】:

问题:使用 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() 也是如此。

Purchase 对象似乎不包含有关其消费的任何信息。 我怎样才能只获得未消费的物品(或至少过滤它们)?

请注意,我知道购买最终必须在我们的服务器端进行管理。然而,在这成功之前,最好知道哪个项目已经“兑换”(消费)了。所以我不能只依赖我们的后端。

---- 编辑----

来自查询的购买对象 (JSON) 都如下所示:

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

所以没有任何东西看起来是一种消费状态。

---- 编辑 2 ----

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

【问题讨论】:

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


    【解决方案1】:

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

    billingClient 有两个方法调用。

    • 第一个是

    billingClient.queryPurchaseHistoryAsync()

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

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

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

    BillingClient 提供:

    billingClient.queryPurchases(BillingClient.SkuType.INAPP)
    

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

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

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

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

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

    【讨论】:

    • 谢谢。我想知道同样的事情,“我如何只获得未消费物品的清单?”应更新 Google 文档以显示 queryPurchases 仅返回未消费的商品。
    • 很高兴为您提供帮助。如果还有其他我没有提出的问题,请告诉我。
    • @TobiasReich “这个异步调用(需要互联网)正在获取用户最近 11 次购买的历史记录”你从哪里得到这个信息?
    • 其实只是观察。不确定这是否记录在某处。它只是为我这样做。
    【解决方案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

    【讨论】:

    • 我认为这是用于后端购买检查,而不是在设备上。嗯,我试一试。谢谢!
    【解决方案3】:
                // 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.");
                    }
                }
            });
    

    【讨论】:

    • 也许可以尝试为您的答案提供事实或解释,请阅读 this 以了解如何编写答案
    • PurchaseHistoryResponseListener 代码非常有用!谢谢!
    • 我没有在我的 queryPurchase 中获得已购买应用程序的 purchaseList。如果购买清单为空,以上内容是否会有所帮助?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-28
    • 1970-01-01
    相关资源
    最近更新 更多