Register now for Android Dev Summit 2019!

使用 Google Play 结算库

本文档阐述了如何使用 Google Play 内容库将 Google Play 结算服务添加到您的应用中。具体来说,本文档介绍了如何添加对所有应用内商品类型(即一次性商品、奖励产品和订阅)通用的 Google Play 结算服务功能。要了解如何将应用内商品专用功能添加到您的应用,请阅读本页末尾列出的文档。

在阅读本页之前,请执行以下操作:

  1. 阅读 Google Play 结算服务概览,熟悉重要的概念和术语。
  2. 使用 Google Play 管理中心配置您的应用内商品:

代码段简介

本指南使用 TrivialDrive v2 示例应用的代码段。此示例展示了如何使用 Play 结算库在赛车游戏中实现应用内商品。该应用演示了如何列出可用商品、启动购买流程、记录商品消耗,以及要将 Google Play 结算服务添加到您的应用中,您需要了解的其他所有信息。图 1 显示了打开该应用时出现的屏幕:

图 1. 打开 Trivial Drive 应用时出现的屏幕。

将 Google Play 结算服务添加到应用的步骤

您可以按照下面几部分中的步骤,将 Google Play 结算服务添加到您的应用。

更新应用的依赖项

将以下行添加到应用的 build.gradle 文件的依赖项部分:

dependencies {
    ...
    implementation 'com.android.billingclient:billing:2.0.1'
}

要确保您使用的是最新版本的 Google Play 结算库,请参阅 Google Play 结算库版本说明

连接到 Google Play

您必须先建立与 Google Play 的连接,然后才能发出 Google Play 结算服务请求,建立连接的具体操作步骤如下:

  1. 调用 newBuilder() 以创建 BillingClient 实例。您还必须调用 setListener(),传递对 PurchasesUpdatedListener 的引用,以接收有关由您的应用发起的购买交易的更新,以及由 Google Play 商店发起的购买交易的更新。

  2. 建立与 Google Play 的连接。设置过程是异步的,您必须实现 BillingClientStateListener,以在客户端设置完成且它已准备好发出进一步请求时接收回调。

  3. 替换 onBillingServiceDisconnected() 回调方法并实现您自己的重试策略,以便在客户端失去连接时处理与 Google Play 失去连接的问题。例如,如果 Google Play 商店服务正在后台更新,那么 BillingClient 可能会失去连接。在发出进一步的请求之前,BillingClient 必须先调用 startConnection() 方法以重启连接。

以下代码示例演示了如何启动连接并测试它是否已可供使用:

Kotlin

lateinit private var billingClient: BillingClient
...
billingClient = BillingClient.newBuilder(context).setListener(this).build()
billingClient.startConnection(object : BillingClientStateListener {
   override fun onBillingSetupFinished(billingResult: BillingResult) {
       if (billingResult.responseCode == BillingResponse.OK) {
           // The BillingClient is ready. You can query purchases here.
       }
   }
   override fun onBillingServiceDisconnected() {
       // Try to restart the connection on the next request to
       // Google Play by calling the startConnection() method.
   }
})

Java

private BillingClient billingClient;
...
billingClient = BillingClient.newBuilder(activity).setListener(this).build();
billingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(BillingResult billingResult) {
        if (billingResult.getResponseCode() == BillingResponse.OK) {
            // The BillingClient is ready. You can query purchases here.
        }
    }
    @Override
    public void onBillingServiceDisconnected() {
        // Try to restart the connection on the next request to
        // Google Play by calling the startConnection() method.
    }
});

查询应用内商品详情

您在配置应用内商品时创建的唯一商品 ID 将用于向 Google Play 异步查询应用内商品详情。要向 Google Play 查询应用内商品详情,请调用 querySkuDetailsAsync()。调用此方法时,传递一个 SkuDetailsParams 实例,该实例将指定商品 ID 字符串的列表和一个 SkuType。该 SkuType 可以是 SkuType.INAPP(针对一次性商品或奖励产品)或 SkuType.SUBS(针对订阅)。

要处理异步操作所得的结果,您还必须指定一个实现 SkuDetailsResponseListener 接口的监听器。然后,您可以替换 onSkuDetailsResponse(),该方法会在查询完成时通知监听器,如以下示例代码所示:

Kotlin

val skuList = ArrayList<String>()
skuList.add("premium_upgrade")
skuList.add("gas")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(SkuType.INAPP)
billingClient.querySkuDetailsAsync(params.build(), { billingResult, skuDetailsList ->
    // Process the result.
})

Java

List<String> skuList = new ArrayList<> ();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
    new SkuDetailsResponseListener() {
        @Override
        public void onSkuDetailsResponse(BillingResult billingResult,
                List<SkuDetails> skuDetailsList) {
            // Process the result.
        }
    });

您的应用应维护它自己的商品 ID 列表,方法是将该列表与您的 APK 捆绑在一起,或者从您自己的安全后端服务器查询。

调用 BillingResult#getResponseCode() 来检索响应代码。如果请求成功,则响应代码为 BillingResponse.OK。如需查看可能来自 Google Play 的其他响应代码的列表,请参阅 BillingClient.BillingResponse

如果发生错误,您可以使用 BillingResult#getDebugMessage() 来查看关联的错误消息。

Google Play 结算库将查询结果存储在 SkuDetails 对象的 List 中。您随后可以在该列表中的每个 SkuDetails 对象上调用各种方法,以查看应用内商品的相关信息,如其价格或说明。要查看可用的商品详情,请参阅 SkuDetails 类中的方法列表。

以下示例显示了如何使用先前代码段返回的 SkuDetails 对象来检索应用内商品的价格:

Kotlin

if (result.responseCode == BillingResponse.OK && skuDetailsList != null) {
    for (skuDetails in skuDetailsList) {
        val sku = skuDetails.sku
        val price = skuDetails.price
        if ("premium_upgrade" == sku) {
            premiumUpgradePrice = price
        } else if ("gas" == sku) {
            gasPrice = price
        }
    }
}

Java

if (result.getResponseCode() == BillingResponse.OK && skuDetailsList != null) {
   for (SkuDetails skuDetails : skuDetailsList) {
       String sku = skuDetails.getSku();
       String price = skuDetails.getPrice();
       if ("premium_upgrade".equals(sku)) {
           premiumUpgradePrice = price;
       } else if ("gas".equals(sku)) {
           gasPrice = price;
       }
   }
}

在用户购买商品之前,检索商品价格是一个重要步骤,因为提供给每个用户的价格因他们所在的国家/地区而异。Trivial Drive 应用以列表的形式显示所有应用内商品,如图 2 中所示:

图 2. Trivial Drive 的应用内商品屏幕。

一致的报价

在提供折扣 SKU 时,Google Play 还会返回 SKU 的原价,以便您向用户显示他们正在享受折扣。我们建议您既使用 getPrice() 向用户显示折扣价,又使用 getOriginalPrice() 显示商品的原价。

SkuDetails 包含两种用来检索 SKU 原价的方法:

启用应用内商品的购买

有些 Android 手机安装的 Google Play 商店应用可能是旧版的,不支持订阅等商品类型。因此,在您的应用进入结算流程之前,请调用 isFeatureSupported() 检查设备是否支持您要销售的商品。如需查看商品类型的列表,请参阅 BillingClient.FeatureType

要从您的应用发起购买请求,请从界面线程调用 launchBillingFlow() 方法,传递对包含相关数据的 BillingFlowParams 对象的引用以完成购买,如商品的商品 ID (skuId) 和商品类型(SkuType.INAPP - 针对一次性商品或奖励产品,或者 SkuType.SUBS - 针对订阅)。要获取 BillingFlowParams 实例,请使用 BillingFlowParams.Builder 类:

Kotlin

// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
val flowParams = BillingFlowParams.newBuilder()
        .setSkuDetails(skuDetails)
        .build()
val responseCode = billingClient.launchBillingFlow(activity, flowParams)

Java

// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
        .setSkuDetails(skuDetails)
        .build();
int responseCode = billingClient.launchBillingFlow(flowParams);

当您调用 launchBillingFlow() 方法时,系统会显示 Google Play 购买屏幕。图 3 显示了一次性商品的购买屏幕:

图 3. 一次性商品的 Google Play 购买屏幕。

图 4 显示了订阅的购买屏幕:

图 4. 订阅的 Google Play 购买屏幕。

launchBillingFlow() 方法会返回 BillingClient.BillingResponse 中列出的几个响应代码之一。Google Play 会调用 onPurchasesUpdated() 方法,将购买操作所得到的结果传送给实现 PurchasesUpdatedListener 接口的监听器。监听器使用 setListener() 方法指定,如前面连接到 Google Play 部分中所示。

您必须实现 onPurchasesUpdated() 方法来处理可能的响应代码。以下代码段显示了如何替换 onPurchasesUpdated() 方法:

Kotlin

override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
   if (billingResult.responseCode == BillingResponse.OK && purchases != null) {
       for (purchase in purchases) {
           handlePurchase(purchase)
       }
   } else if (billingResult.responseCode == BillingResponse.USER_CANCELED) {
       // Handle an error caused by a user cancelling the purchase flow.
   } else {
       // Handle any other error codes.
   }
}

Java

@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
    if (billingResult.getResponseCode() == BillingResponse.OK
            && purchases != null) {
        for (Purchase purchase : purchases) {
            handlePurchase(purchase);
        }
    } else if (billingResult.getResponseCode() == BillingResponse.USER_CANCELED) {
        // Handle an error caused by a user cancelling the purchase flow.
    } else {
        // Handle any other error codes.
    }
}

如果成功购买商品,系统会显示 Google Play 购买成功屏幕,类似于图 5 中的屏幕。

图 5. Google Play 购买成功屏幕。

如果商品购买成功,系统还会生成购买令牌,它是一个唯一标识符,表示用户及其所购应用内商品的商品 ID。您的应用可以在用户设备上存储购买令牌,理想情况下,也可以将购买令牌传递到安全的后端服务器,以便用于验证购买交易及防范欺诈行为。购买令牌对于一次性商品的每笔购买交易和每个奖励产品都是唯一的。不过,由于订阅是一次性购买并按固定的结算周期自动续订,因此订阅的购买令牌在各个结算周期内保持不变。

用户还会收到包含交易收据的电子邮件,其中包含订单 ID 或交易的唯一 ID。用户每次购买一次性商品时,都会收到包含唯一订单 ID 的电子邮件。此外,用户最初购买订阅时以及后续定期自动续订时,也会收到这样的电子邮件。您可以在 Google Play 管理中心内使用订单 ID 来管理退款。有关详情,请参阅查看应用的订单和订阅及办理退款

确认购买交易

如果您使用的是 Google Play 结算库版本 2.0 或更高版本,则必须在三天内确认所有购买交易。如果没能正确确认,将导致系统对相应购买交易按退款处理。

Google Play 支持从您的应用内部(应用内)或您的应用外部(应用外)购买商品。为了确保无论用户在哪里购买您的商品,Google Play 都能提供一致的购买体验,您必须在授予用户权利后尽快确认通过 Google Play 结算库收到的所有处于 SUCCESS 状态的购买交易。如果您在三天内未确认购买交易,则用户会自动收到退款,并且 Google Play 会撤消该购买交易。对于待处理的交易,当购买交易处于 PENDING 状态时,三天的期限不适用,而是从购买交易改为 SUCCESS 状态时起算。

您可以使用以下某种方法来确认购买交易:

  • 对于消耗型商品,请使用客户端 API 中的 consumeAsync()
  • 对于非消耗型商品,请使用客户端 API 中的 acknowledgePurchase()
  • 还可以使用服务器 API 中新增的 acknowledge() 方法。

对于订阅,您必须确认包含新购买令牌的任何购买交易。这意味着,需要确认所有初始购买、计划变更和重新注册,但无需确认后续续订。要确定购买交易是否需要确认,您可以检查购买交易中的确认字段。

Purchase 对象包含 isAcknowledged() 方法,该方法可指示购买交易是否已得到确认。此外,服务器端 API 包含 Product.purchases.get()Product.subscriptions.get() 的确认布尔值。在确认购买交易之前,请使用这些方法来确定购买交易是否已得到确认。

以下示例显示了如何确认订阅购买交易:

Kotlin

val client: BillingClient = ...
val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ...

fun handlePurchase() {
    if (purchase.state === PurchaseState.PURCHASED) {
        // Grant entitlement to the user.
        ...

        // Acknowledge the purchase if it hasn't already been acknowledged.
        if (!purchase.isAcknowledged) {
            val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.purchaseToken)
                    .build()
            client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener)
        }
     }
}

Java

BillingClient client = ...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...

void handlePurchase(Purchase purchase) {
    if (purchase.getState() == PurchaseState.PURCHASED) {
        // Grant entitlement to the user.
        ...

        // Acknowledge the purchase if it hasn't already been acknowledged.
        if (!purchase.isAcknowledged()) {
            AcknowledgePurchaseParams acknowledgePurchaseParams =
                AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.getPurchaseToken())
                    .build();
            client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
        }
    }
}

让许可测试人员测试确认购买交易

对于许可测试人员进行的购买交易,确认期限会更短。如果未在 5 分钟(而不是三天)内得到确认,购买交易便会被退款并撤消。

支持待处理的交易

在实现 Google Play 结算服务解决方案时,您必须支持在授予权利之前需要执行其他操作的购买交易。例如,用户可能会选择使用现金在实体店购买您的应用内商品。这意味着,交易在您的应用外部完成。在这种情况下,只有在用户完成交易后,您才能授予权利。

要启用待处理的购买交易,请在初始化您的应用时调用 enablePendingPurchases()。请注意,如果您未调用 enablePendingPurchases(),则无法实例化 Google Play 结算库。

使用 Purchase.getState() 方法确定购买状态是 PURCHASED 还是 PENDING。请注意,只有在状态为 PURCHASED 时,您才能授予权利。您可以执行以下操作来检查状态变化:

  1. 在启动您的应用时,调用 BillingClient.queryPurchases() 以检索与用户关联的非消耗型商品的列表,然后在返回的每个 Purchase 对象上调用 getState()
  2. 实现 onPurchasesUpdated() 方法以响应对 Purchase 对象的更改。

以下示例演示了您可以如何处理待处理的交易:

Kotlin

fun handlePurchase(purchase: Purchase) {
    if (purchase.state == PurchaseState.PURCHASED) {
        // Grant the item to the user, and then acknowledge the purchase
    } else if (purchase.state == PurchaseState.PENDING) {
        // Here you can confirm to the user that they've started the pending
        // purchase, and to complete it, they should follow instructions that
        // are given to them. You can also choose to remind the user in the
        // future to complete the purchase if you detect that it is still
        // pending.
    }
}

Java

void handlePurchase(Purchase purchase) {
    if (purchase.getState() == PurchaseState.PURCHASED) {
        // Acknowledge purchase and grant the item to the user
    } else if (purchase.getState() == PurchaseState.PENDING) {
        // Here you can confirm to the user that they've started the pending
        // purchase, and to complete it, they should follow instructions that
        // are given to them. You can also choose to remind the user in the
        // future to complete the purchase if you detect that it is still
        // pending.
    }
}

让许可测试人员测试待处理的交易

待处理的交易可由许可测试人员进行测试。除了两张测试信用卡之外,许可测试人员还可以使用两种测试付款方式,以测试在几分钟后自动完成或取消的延迟付款方式。

在测试您的应用时,您应验证您的应用是否不会在用户使用这两种付款方式中的任意一种购买后立即授予权利或确认购买交易。使用自动完成的测试付款方式购买时,您应验证您的应用是否会在购买完成后授予权利并确认购买交易。

在使用自动取消的测试付款方式购买时,您应验证您的应用不会授予权利,因为此时没有成功的购买交易。

附加开发者有效负载

您可以将任意字符串(即开发者有效负载)附加到购买交易。但请注意,只有在已确认购买交易或已消耗所购商品时,才能附加开发者有效负载。这与 AIDL 中的开发者有效负载不同,在 AIDL 中,可以在启动购买流程时指定有效负载。

对于消耗型商品,consumeAsync() 接受包含开发者有效负载字段的 ConsumeParams 对象,如以下示例中所示:

Kotlin

val client: BillingClient = ...
val listener: ConsumeResponseListener = ...

val consumeParams =
    ConsumeParams.newBuilder()
        .setPurchaseToken(/* token */)
        .setDeveloperPayload(/* payload */)
        .build()

client.consumeAsync(consumeParams, listener)

Java

BillingClient client = ...
ConsumeResponseListener listener = ...

ConsumeParams consumeParams =
    ConsumeParams.newBuilder()
        .setPurchaseToken(/* token */)
        .setDeveloperPayload(/* payload */)
        .build();

client.consumeAsync(consumeParams, listener);

对于非消耗型商品,acknowledgePurchase() 接受包含开发者有效负载字段的 AcknowledgePurchaseParams 对象,如以下示例中所示:

Kotlin

val client: BillingClient = ...
val listener: AcknowledgePurchaseResponseListener = ...

val acknowledgePurchaseParams =
    AcknowledgePurchaseParams.newBuilder()
        .setPurchaseToken(/* token */)
        .setDeveloperPayload(/* payload */)
        .build()

client.acknowledgePurchase(acknowledgePurchaseParams, listener)

Java

BillingClient client = ...
AcknowledgePurchaseResponseListener listener = ...

AcknowledgePurchaseParams acknowledgePurchaseParams =
    AcknowledgePurchaseParams.newBuilder()
        .setPurchaseToken(/* token */)
        .setDeveloperPayload(/* payload */)
        .build();

client.acknowledgePurchase(acknowledgePurchaseParams, listener);

要访问开发者有效负载,请在相应的 Purchase 对象上调用 getDeveloperPayload()

您只能消耗或确认处于 PURCHASED 购买状态的购买交易。

验证购买交易

在向用户提供对其所购商品的访问权限之前,您应始终验证相应购买交易是否处于 PURCHASED 状态,并验证您的应用在 onPurchasesUpdated() 中收到的其他购买详情。

在服务器上验证购买交易

通过在服务器上实现购买验证逻辑,您可以保护您的应用,让企图对您的 APK 文件进行逆向工程并停用其验证逻辑的攻击者无计可施。要在安全后端服务器上验证购买详情,请完成以下步骤:

  1. 从您的应用中,将购买令牌和用户帐号凭据发送到您的安全后端服务器。验证成功后,安全后端服务器应将购买交易与用户关联。

  2. 从应用获取令牌后:

    1. 使用 Google Play Developer API 的订阅和购买交易部分执行 GET 请求,以从 Google Play 检索购买详情(Purchases.products - 针对一次性商品的购买交易或奖励产品的购买交易,或者 Purchases.subscriptions - 针对订阅)。GET 请求包含应用软件包名称、商品 ID 和令牌(即购买令牌)。

    2. Google Play 将返回购买详情。

    3. 安全后端服务器将验证订单 ID 是否为不代表先前购买交易的唯一值。

    4. 安全后端服务器使用在第 1 步中收到的用户帐号凭据,将购买令牌与发起购买时所在的应用实例的用户关联。

    5. (可选)如果您正在验证订阅,并且订阅正在升级、降级或用户在订阅失效前已重新订阅,请查看 linkedPurchaseToken 字段。Purchases.subscriptions 资源中的 linkedPurchaseToken 字段包含上一笔(即“原始”)购买交易的令牌。如需详细了解 linkedPurchaseToken,请参阅 Purchases.subscriptions

    6. 应用内商品可供用户使用。

在设备上验证购买交易

如果您无法运行自己的服务器,仍可在您的 Android 应用中验证购买详情。

为了帮助确保发送到您应用的交易信息的完整性,Google Play 会为包含购买交易响应数据的 JSON 字符串签名。Google Play 会使用 Play 管理中心内与您的应用关联的私钥来创建此签名。Play 管理中心会为每个应用分别生成一个 RSA 密钥对。您可以使用 Purchase 类中的 getOriginalJson() 方法来获取此响应 JSON。

由 Google Play 生成的以 Base64 编码的 RSA 公钥采用二进制编码的 X.509 subjectPublicKeyInfo DER SEQUENCE 格式。它与 Google Play 许可使用的公钥相同。

当您的应用收到带签名的这一响应后,您可以使用 RSA 密钥对的公钥部分来验证签名。通过执行签名验证,您可以检测到任何被篡改或假冒的响应。

您应对 Google Play 公钥和 Google Play 结算服务代码进行混淆处理,让攻击者难以对安全协议及其他应用组件进行逆向工程。我们建议您至少对代码运行 Proguard 等代码混淆工具。要使用 Proguard 对代码进行混淆处理,您必须将以下行添加到 Proguard 配置文件:

-keep class com.android.vending.billing.**

对 Google Play 公钥和 Google Play 结算服务代码进行混淆处理后,您就可以让您的应用验证购买详情了。当您的应用验证签名时,请确保您应用的密钥已为该签名中包含的 JSON 数据签名。

让购买交易保持最新

有时可能无法跟踪用户发起过哪些购买交易。下面给出了两种情况,在第一种情况下,您的应用可能无法跟踪购买交易,在第二种情况下,查询购买交易非常重要。

处理服务器中断

  1. 用户购买一次性商品,如在赛车游戏中购买额外的汽油。
  2. 应用将购买令牌发送到安全后端服务器以进行验证。
  3. 服务器暂时关闭。
  4. 应用识别出服务器已关闭,并通知用户购买交易出现问题。
  5. Android 应用重试将购买令牌发送到安全后端服务器,并在服务器恢复后立即完成购买交易。
  6. 应用发布相应内容。

处理多部设备

  1. 用户在其 Android 手机上购买订阅。
  2. 应用将购买令牌发送到安全后端服务器以进行验证。
  3. 服务器验证购买令牌。
  4. 应用发布相应内容。
  5. 用户切换到 Android 平板电脑以使用订阅。
  6. 新设备上的应用查询更新的购买交易列表。
  7. 应用识别出订阅,并授予在平板电脑上使用它的权限。

查询缓存的购买交易

要检索用户通过您的应用发起的购买交易的相关信息,请调用 queryPurchases();具体方法是使用购买类型(SkuType.INAPPSkuType.SUBS)在 BillingClient 上进行调用,如以下示例中所示:

Kotlin

val purchasesResult: PurchasesResult =
        billingClient.queryPurchases(SkuType.INAPP)

Java

PurchasesResult purchasesResult = billingClient.queryPurchases(SkuType.INAPP);

Google Play 会返回登录到设备的用户帐号发起的购买交易。如果请求成功,则 Play 结算库会将查询结果存储在 Purchase 对象的 List 中。

要检索此列表,请在 PurchasesResult 上调用 getPurchasesList()。您随后可以在 Purchase 对象上调用各种方法,以查看商品的相关信息,如其购买状态或时间。要查看可用的商品类型详情,请参阅 Purchase 类中的方法列表。

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

  • 在每次启动您的应用时都调用 queryPurchases(),以便您可以恢复用户自应用上次停止以来发起的任何购买交易。
  • onResume() 方法中调用 queryPurchases(),因为当您的应用在后台时,用户可能会发起购买交易(例如,在 Google Play 商店应用中兑换促销代码)。

在启动和恢复时调用 queryPurchases() 可以保证您的应用了解用户在其未运行时可能发起的所有购买交易和兑换的相关信息。此外,如果用户在应用运行时发起购买交易,但您的应用由于某种原因而未能跟踪,那么仍然可以在 Activity 下一次恢复并调用 queryPurchases() 时了解该购买交易的相关信息。

查询最近的购买交易

queryPurchases() 方法使用 Google Play 商店应用的缓存,而不发起网络请求。如果您需要查看用户对每个商品 ID 发起的最近一笔购买交易,您可以使用 queryPurchaseHistoryAsync(),并传递购买类型和 PurchaseHistoryResponseListener 以处理查询结果。

queryPurchaseHistoryAsync() 将返回一个 PurchaseHistory 对象,该对象包含用户对每个商品 ID 发起的最近一笔购买交易的相关信息,即使该购买交易已过期、已取消或所购商品已消耗。应尽可能使用 queryPurchases()(而不是 queryPurchaseHistoryAsync()),因为该方法使用本地缓存。如果使用 queryPurchaseHistoryAsync(),您也可以将其与刷新按钮结合使用,从而允许用户更新其购买交易列表。

以下代码演示了如何替换 onPurchaseHistoryResponse() 方法:

Kotlin

billingClient.queryPurchaseHistoryAsync(SkuType.INAPP, { billingResult, purchasesList ->
   if (billingResult.responseCode == BillingResponse.OK && purchasesList != null) {
       for (purchase in purchasesList) {
           // Process the result.
       }
   }
})

Java

billingClient.queryPurchaseHistoryAsync(SkuType.INAPP,
                                         new PurchaseHistoryResponseListener() {
    @Override
    public void onPurchaseHistoryResponse(BillingResult billingResult,
                                          List<Purchase> purchasesList) {
        if (billingResult.getResponseCode() == BillingResponse.OK
                && purchasesList != null) {
            for (Purchase purchase : purchasesList) {
                // Process the result.
            }
         }
    }
});

后续步骤

在您能够允许用户购买您的商品后,您应该学习在特定于商品的场景中具体如何操作: