本文档介绍了如何将 Google Play 结算库集成到您的应用中以开始销售商品。
购买交易的生命周期
下面是一次性购买或订阅的典型购买流程。
- 向用户展示他们可以购买什么。
- 启动购买流程,以便用户接受购买交易。
- 在您的服务器上验证购买交易。
- 向用户提供内容。
- 确认内容已传送给用户。对于消耗型商品,用户要先消耗掉已购商品,才能再次购买。
订阅会自动续订,直到被取消。订阅可处于下面这几种状态:
- 有效:用户信誉良好,可享用订阅内容。
- 已取消:用户已取消订阅,但在到期前仍可享用订阅内容。
- 处于宽限期:用户遇到了付款问题,但仍可享用订阅内容,同时 Google 会重新尝试通过相应的付款方式扣款。
- 暂时保留:用户遇到了付款问题,不能再享用订阅内容,同时 Google 会重新尝试通过相应的付款方式扣款。
- 已暂停:用户暂停了其订阅,在恢复之前不能享用订阅内容。
- 已到期:用户已取消且不能再享用订阅内容。用户在订阅到期时会被视为流失。
初始化与 Google Play 的连接
与 Google Play 结算系统集成的第一步是将 Google Play 结算库添加到您的应用并初始化连接。
添加 Google Play 结算库依赖项
将 Google Play 结算库依赖项添加到应用的 build.gradle 文件中,如下所示:
Groovy
dependencies { def billing_version = "8.0.0" implementation "com.android.billingclient:billing:$billing_version" }
Kotlin
dependencies { val billing_version = "8.0.0" implementation("com.android.billingclient:billing:$billing_version") }
如果您使用的是 Kotlin,Google Play 结算库 KTX 模块包含了 Kotlin 扩展和协程支持,可让您在使用 Google Play 结算库时编写惯用的 Kotlin 代码。如需将这些扩展包含在项目中,请将以下依赖项添加到应用的 build.gradle 文件中,如下所示:
Groovy
dependencies { def billing_version = "8.0.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
Kotlin
dependencies { val billing_version = "8.0.0" implementation("com.android.billingclient:billing-ktx:$billing_version") }
初始化 BillingClient
添加对 Google Play 结算库的依赖项后,您需要初始化 BillingClient 实例。BillingClient 是 Google Play 结算库与应用的其余部分之间进行通信的主接口。BillingClient 为许多常见的结算操作提供了方便的方法,既有同步方法,又有异步方法。请注意以下几点:
- 建议您一次打开一个活跃的
BillingClient连接,以避免对某一个事件进行多次PurchasesUpdatedListener回调。 - 建议在应用启动或进入前台时,为 BillingClient 启动连接,以确保应用及时处理购买交易。为此,您可以使用由
registerActivityLifecycleCallbacks注册的ActivityLifecycleCallbacks,并在首次检测到 activity 恢复时监听 onActivityResumed 以初始化连接。如需详细了解为何应遵循此最佳实践,请参阅有关处理购买交易的部分。另请注意,当应用关闭时,请务必结束连接。
如需创建 BillingClient,请使用 newBuilder。您可以将任何上下文传递给 newBuilder(),以供 BillingClient 用于获取应用上下文。这意味着您不必担心内存泄漏。为了接收有关购买交易的更新,您还必须调用 setListener,并传递对 PurchasesUpdatedListener 的引用。此监听器可接收应用中所有购买交易的更新。
Kotlin
private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases -> // To be implemented in a later section. } private var billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build()
Java
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() { @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { // To be implemented in a later section. } }; private BillingClient billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build();
连接到 Google Play
创建 BillingClient 后,您需要与 Google Play 建立连接。
如需连接到 Google Play,请调用 startConnection。连接过程是异步进行的,因此您必须实现 BillingClientStateListener,以便在客户端的设置完成后且它准备好发出进一步的请求时接收回调。
此外,您还必须实现重试逻辑,以处理与 Google Play 失去连接的问题。如需实现重试逻辑,请替换 onBillingServiceDisconnected() 回调方法,并确保 BillingClient 先调用 startConnection() 方法以重新连接到 Google Play,然后再发出进一步的请求。
以下示例演示了如何启动连接并测试它是否已准备就绪可供使用:
Kotlin
billingClient.startConnection(object : BillingClientStateListener { override fun onBillingSetupFinished(billingResult: BillingResult) { if (billingResult.responseCode == BillingResponseCode.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
billingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(BillingResult billingResult) { if (billingResult.getResponseCode() == BillingResponseCode.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. } });
自动重新建立连接
随着版本 8.0.0 中引入了 BillingClient.Builder 中的 enableAutoServiceReconnection() 方法,如果服务断开连接时进行了 API 调用,Play 结算库现在可以自动重新建立服务连接。由于在进行 API 调用之前,系统会在内部处理重新连接,因此这可能会导致 SERVICE_DISCONNECTED 响应减少。
如何启用自动重新连接
构建 BillingClient 实例时,请使用 BillingClient.Builder 中的 enableAutoServiceReconnection() 方法来启用自动重新连接。
Kotlin
val billingClient = BillingClient.newBuilder(context)
.setListener(listener)
.enablePendingPurchases()
.enableAutoServiceReconnection() // Add this line to enable reconnection
.build()
Java
BillingClient billingClient = BillingClient.newBuilder(context)
.setListener(listener)
.enablePendingPurchases()
.enableAutoServiceReconnection() // Add this line to enable reconnection
.build();
展示可供购买的商品
与 Google Play 建立连接后,您就可以查询可售的商品并将其展示给用户了。
在将商品展示给用户之前,查询商品详情是非常重要的一步,因为查询会返回本地化的商品信息。对于订阅,请验证您的商品展示符合所有 Play 政策。
如需查询一次性商品详情,请调用 queryProductDetailsAsync 方法。此方法可以根据您的一次性商品配置返回多个优惠。如需了解详情,请参阅一次性商品的多项购买选项和优惠。
为了处理该异步操作的结果,您还必须指定实现 ProductDetailsResponseListener 接口的监听器。然后,您可以替换 onProductDetailsResponse,该方法会在查询完成时通知监听器,如以下示例所示:
Kotlin
val queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build() billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult, queryProductDetailsResult -> if (billingResult.getResponseCode() == BillingResponseCode.OK) { for (ProductDetails productDetails : queryProductDetailsResult.getProductDetailsList()) { // Process successfully retrieved product details here. } for (UnfetchedProduct unfetchedProduct : queryproductDetailsResult.getUnfetchedProductList()) { // Handle any unfetched products as appropriate. } } }
Java
QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build(); billingClient.queryProductDetailsAsync( queryProductDetailsParams, new ProductDetailsResponseListener() { public void onProductDetailsResponse(BillingResult billingResult, QueryProductDetailsResult queryProductDetailsResult) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { for (ProductDetails productDetails : queryProductDetailsResult().getProductDetailsList()) { // Process success retrieved product details here. } for (UnfetchedProduct unfetchedProduct : queryproductDetailsResult.getUnfetchedProductList()) { // Handle any unfetched products as appropriate. } } } } )
查询商品详情时,应传递 QueryProductDetailsParams 的实例,用于指定在 Google Play 管理中心内创建的商品 ID 字符串列表以及 ProductType。ProductType 可以是 ProductType.INAPP(针对一次性商品),也可以是 ProductType.SUBS(针对订阅)。
使用 Kotlin 扩展程序进行查询
如果您使用 Kotlin 扩展,可以通过调用 queryProductDetails() 扩展函数查询一次性商品详情。
queryProductDetails() 会利用 Kotlin 协程,因此您无需定义单独的监听器。相反,该函数会挂起,直到查询完成,然后您可以处理查询结果:
suspend fun processPurchases() {
val productList = listOf(
QueryProductDetailsParams.Product.newBuilder()
.setProductId("product_id_example")
.setProductType(BillingClient.ProductType.SUBS)
.build()
)
val params = QueryProductDetailsParams.newBuilder()
params.setProductList(productList)
// leverage queryProductDetails Kotlin extension function
val productDetailsResult = withContext(Dispatchers.IO) {
billingClient.queryProductDetails(params.build())
}
// Process the result.
}
在极少数情况下,某些设备无法支持 ProductDetails 和 queryProductDetailsAsync(),这通常是因为 Google Play 服务版本已过时。为确保对此场景提供适当的支持,请参阅 Play 结算库版本 7 迁移指南,了解如何使用向后兼容的功能。
处理查询结果
Google Play 结算库会将查询结果存储在 QueryProductDetailsResult 对象中。QueryProductDetailsResult 包含 ProductDetails 对象的 List。您随后可以对该列表中的每个 ProductDetails 对象调用各种方法,以查看成功提取的一次性商品的相关信息,如其价格或说明。如需查看可用的商品详情,请参阅 ProductDetails 类中的方法列表。
QueryProductDetailsResult 还包含 UnfetchedProduct 对象的 List。然后,您可以查询每个 UnfetchedProduct,以获取与提取失败原因对应的状态代码。如需查看可用的未提取商品信息,请参阅 UnfetchedProduct 类中的方法列表。
在提供待售商品之前,检查用户是否尚未拥有该商品。如果用户的消耗型商品仍在其商品库中,用户必须先消耗掉该商品,然后才能再次购买。
在提供订阅之前,验证用户是否尚未订阅。此外,还请注意以下事项:
对于订阅,
queryProductDetailsAsync()方法会返回订阅商品详情,并且每项订阅最多包含 50 个用户符合条件的优惠。如果用户尝试购买不符合条件的优惠(例如,应用显示的是过时的可享优惠列表),Play 会通知用户其不符合优惠条件,并且用户可以改为选择购买基础方案。对于一次性商品,
queryProductDetailsAsync()方法仅返回用户有资格享受的优惠。如果用户尝试购买他们没有资格享受的优惠(例如,用户已达到购买数量上限),Play 会通知用户他们不符合优惠条件,并且用户可以改为选择购买其购买选项优惠。
启动购买流程
如需从应用发起购买请求,请从应用的主线程调用 launchBillingFlow() 方法。此方法接受对 BillingFlowParams 对象的引用,该对象包含通过调用 queryProductDetailsAsync 获取的相关 ProductDetails 对象。如需创建 BillingFlowParams 对象,请使用 BillingFlowParams.Builder 类。
Kotlin
// An activity reference from which the billing flow will be launched. val activity : Activity = ...; val productDetailsParamsList = listOf( BillingFlowParams.ProductDetailsParams.newBuilder() // retrieve a value for productDetails by calling queryProductDetailsAsync() .setProductDetails(productDetails) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, call ProductDetails.subscriptionOfferDetails() // for a list of offers that are available to the user. .setOfferToken(selectedOfferToken) .build() ) val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build() // Launch the billing flow val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Java
// An activity reference from which the billing flow will be launched. Activity activity = ...; ImmutableList<ProductDetailsParams> productDetailsParamsList = ImmutableList.of( ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, call ProductDetails.subscriptionOfferDetails() // for a list of offers that are available to the user. .setOfferToken(selectedOfferToken) .build() ); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); // Launch the billing flow BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
launchBillingFlow() 方法会返回 BillingClient.BillingResponseCode 中列出的几个响应代码之一。请务必检查此结果,以验证在启动购买流程时没有错误。BillingResponseCode 为 OK 表示成功启动。
成功调用 launchBillingFlow() 后,系统会显示 Google Play 购买界面。图 1 显示了一项订阅的购买界面:
Google Play 会调用 onPurchasesUpdated(),以将购买操作的结果传送给实现 PurchasesUpdatedListener 接口的监听器。您可以在初始化客户端时使用 setListener() 方法指定监听器。
您必须实现 onPurchasesUpdated() 来处理可能的响应代码。以下示例展示了如何替换 onPurchasesUpdated():
Kotlin
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) { if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) { for (purchase in purchases) { // Process the purchase as described in the next section. } } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling the purchase flow. } else { // Handle any other error codes. } }
Java
@Override void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { // Process the purchase as described in the next section. } } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling the purchase flow. } else { // Handle any other error codes. } }
如果成功购买商品,系统会显示 Google Play 购买成功界面,类似于图 2。
如果成功购买商品,系统还会生成购买令牌,它是一个唯一标识符,表示用户及其所购一次性商品的商品 ID。应用可以在本地存储购买令牌,不过我们强烈建议您将令牌传递到安全的后端服务器,您随后可以在该服务器上验证购买交易及防范欺诈行为。如需详细了解此流程,请参阅检测和处理购买交易。
用户还会收到包含交易收据的电子邮件,收据内含订单 ID 或交易的唯一 ID。用户每次购买一次性商品时,都会收到包含唯一订单 ID 的电子邮件。此外,用户最初购买订阅时以及后续定期自动续订时,也会收到这样的电子邮件。您可以在 Google Play 管理中心内使用订单 ID 来管理退款。
标明个性化价格
如果应用可能会面向欧盟用户分发,请在调用 launchBillingFlow 时使用 setIsOfferPersonalized() 方法向用户披露您的商品价格已通过自动化决策进行了个性化设置。
您必须参阅《欧盟消费者权益指令》2011/83/EU 6 (1) (ea) CRD 条款,确定您向用户提供的价格是否进行了个性化设置。
setIsOfferPersonalized() 接受布尔值输入。当该值为 true 时,Play 界面会包含披露声明。当该值为 false 时,Play 界面会忽略披露声明。默认值为 false。
如需了解详情,请参阅消费者帮助中心。
附加用户标识符
当您启动购买流程时,您的应用可以使用 obfuscatedAccountId 或 obfuscatedProfileId 附加您拥有的购买用户的任何用户标识符。标识符示例可以是用户在您系统中的登录名的混淆版本。设置这些参数有助于 Google 检测欺诈行为。此外,它还可以帮助您确保购买交易归因于正确的用户,如向用户授予使用权中所述。
检测和处理购买交易
本部分中描述的购买交易检测和处理适用于所有类型的购买交易,包括应用外购买交易(如促销活动兑换)。
您的应用可以通过以下方式之一检测新的购买交易和已完成的待处理购买交易:
- 当
onPurchasesUpdated因应用调用launchBillingFlow(如上一部分所述)而被调用时,或者当您的应用在有应用外购买交易或待处理的购买交易完成时,正在运行且与结算库的连接处于有效状态时,系统会调用onPurchasesUpdated。例如,家庭成员在另一台设备上批准了待处理的购买交易。 - 当应用调用 queryPurchasesAsync 来查询用户的购买交易时。
对于第 1 步,只要您的应用正在运行并具有有效的 Google Play 结算库连接,系统就会自动针对新购买交易或已完成的购买交易调用 onPurchasesUpdated。如果您的应用未运行,或者您的应用没有有效的 Google Play 结算库连接,则不会调用 onPurchasesUpdated。请注意,建议您的应用在前台运行时,尽可能保持有效连接,以便及时获取购买交易更新。
对于第 2 步,您必须调用 BillingClient.queryPurchasesAsync(),以确保您的应用处理所有购买交易。建议您在应用成功与 Google Play 结算库建立连接时执行此操作(建议在应用启动或进入前台时执行此操作,如初始化 BillingClient 中所述)。为此,您可以在收到 onServiceConnected 的成功结果时调用 queryPurchasesAsync。遵循此建议对于处理以下事件和情况至关重要:
- 在购买过程中出现网络问题:用户可以成功购买商品并收到 Google 的确认消息,但他们的设备在通过
PurchasesUpdatedListener收到购买交易的通知之前失去了网络连接。 - 多台设备:用户可能在一台设备上购买了一件商品,然后在切换设备时期望看到该商品。
- 处理在您的应用外进行的购买交易:某些购买交易(如促销活动兑换)可能会在您的应用外进行。
- 处理购买状态转换:用户可能会在您的应用未运行时完成对 PENDING 购买交易的付款,并希望在打开您的应用时收到购买完成确认。
一旦应用检测到新的购买交易或已完成的购买交易,就应执行以下操作:
- 验证购买交易。
- 针对已完成的购买交易向用户授予内容。
- 通知用户。
- 通知 Google 您的应用已处理完成的购买交易。
以下各部分将详细讨论这些步骤,最后一部分将总结所有步骤。
验证购买交易
在向用户授予福利之前,您的应用应始终验证购买交易的合法性。为此,您可以按照在授予权利前验证购买交易中所述的准则进行操作。只有在验证购买交易后,您的应用才能继续处理购买交易并向用户授予权利,这将在下一部分中讨论。
向用户授予使用权
应用验证购买交易后,可以继续向用户授予使用权并通知用户。在授予权利之前,请验证您的应用是否正在检查购买交易的状态是否为 PURCHASED。如果购买交易处于 PENDING 状态,您的应用应通知用户,他们仍需完成一些操作才能完成购买交易,然后才能获得相应权利。只有在购买交易从 PENDING 转换为 SUCCESS 时,才授予权利。
如需了解详情,请参阅处理待处理的交易。
如果您已按照附加用户标识符中所述将用户标识符附加到购买交易,则可以检索并使用这些标识符在您的系统中归因给正确的用户。当您的应用可能丢失了有关购买交易是为哪个用户进行的上下文信息时,此方法在协调购买交易方面非常有用。请注意,在您的应用外进行的购买交易不会设置这些标识符。在这种情况下,您的应用可以向已登录的用户授予使用权,也可以提示用户选择首选账号。
对于预订,在到达发布时间之前,购买交易处于“待处理”状态。预订购买交易将在发布时完成,并将状态更改为“已购买”,无需执行其他操作。
通知用户
在向用户授予使用权后,您的应用应显示一条通知,确认购买交易已成功完成。由于有通知,用户不会对购买交易是否成功完成感到困惑,否则可能会导致用户停止使用您的应用、与用户支持团队联系,或在社交媒体上抱怨。请注意,您的应用可能会在应用生命周期的任何时间检测到购买交易更新。例如,家长在另一部设备上批准了待处理的购买交易,在这种情况下,您的应用可能希望延迟向用户发送通知,直到合适的时间再发送。以下是一些适合使用延迟的示例:
- 当用户在玩游戏或观看过场动画时,显示消息可能会让用户分心。在这种情况下,必须待游戏结束后再通知用户。
- 当用户在游戏中学习初始教程和进行用户设置时。例如,用户可能在安装您的应用之前已在应用外进行过购买交易。我们建议您在新用户打开游戏后立即将奖励告知用户,或在用户进行初始设置期间告知他们。如果您的应用要求用户先创建账号或登录,然后才能授予用户使用权,建议您告知用户完成哪些步骤才能领取其购买的商品。这一点至关重要,因为如果您的应用未处理购买交易,系统会在 3 天后退款。
在通知用户有关购买交易时,Google Play 建议采用以下机制:
- 显示应用内对话框。
- 将消息传送到应用内消息箱,并清楚地指出应用内消息箱中有新消息。
- 使用操作系统通知消息。
通知应告知用户其获得的福利。例如,“您购买了 100 个金币!”。此外,如果购买交易是因 Play Pass 等计划的福利而产生的,您的应用会将此信息传达给用户。例如,“已收到商品!您刚刚使用 Play Pass 兑换了 100 颗宝石。 继续。”。每个计划都可能会提供有关向用户显示哪些推荐文本来传达福利的指南。
通知 Google 购买交易已处理
在您的应用向用户授予使用权并通知用户交易成功后,您的应用需要通知 Google 购买交易已成功处理。为此,您需要确认购买交易,并且必须在三天内完成此操作,以免系统自动退款并撤消相应授权。以下部分介绍了确认不同类型购买交易的流程。
消耗型商品
对于消耗型商品,如果您的应用具有安全后端,我们建议您使用 Purchases.products:consume 可靠地消耗所购商品。若要确保所购商品未被消耗掉,请查看 Purchases.products:get 调用结果中的 consumptionState。如果您的应用只有客户端而没有后端,请使用 Google Play 结算库中的 consumeAsync()。这两种方法都符合确认要求,并且表明您的应用已将使用权授予用户。这些方法也支持您的应用提供与输入购买令牌对应的一次性商品,供用户再次购买。如果使用 consumeAsync(),您还必须传递一个实现 ConsumeResponseListener 接口的对象。该对象用于处理消耗操作的结果。您可以替换 onConsumeResponse() 方法,Google Play 结算库会在消耗操作完成时调用该方法。
以下示例展示了如何使用关联的购买令牌,通过 Google Play 结算库来消耗商品:
Kotlin
val consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build() val consumeResult = withContext(Dispatchers.IO) { client.consumePurchase(consumeParams) }
Java
ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); ConsumeResponseListener listener = new ConsumeResponseListener() { @Override public void onConsumeResponse(BillingResult billingResult, String purchaseToken) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { // Handle the success of the consume operation. } } }; billingClient.consumeAsync(consumeParams, listener);
非消耗型商品
如需确认非消耗型商品的购买交易,如果您的应用具有安全后端,我们建议您使用 Purchases.products:acknowledge 可靠地确认购买交易。若要确保购买交易尚未确认,请查看 Purchases.products:get 调用结果中的 acknowledgementState。
如果您的应用只有客户端,请在应用中使用 Google Play 结算库中的 BillingClient.acknowledgePurchase()。在确认购买交易之前,您的应用应检查它是否已通过使用 Google Play 结算库中的 isAcknowledged() 方法进行确认。
以下示例展示了如何使用 Google Play 结算库来确认购买交易:
Kotlin
val client: BillingClient = ... val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ... val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.purchaseToken) val ackPurchaseResult = withContext(Dispatchers.IO) { client.acknowledgePurchase(acknowledgePurchaseParams.build()) }
Java
BillingClient client = ... AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ... AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
订阅
订阅的处理方式与非消耗型商品类似。如果可能,请使用 Google Play Developer API 中的 Purchases.subscriptions.acknowledge 通过安全后端可靠地确认购买交易。若要验证购买交易尚未确认,请通过 Purchases.subscriptions:get 查看购买资源中的 acknowledgementState。另外,您也可以在查看 isAcknowledged() 后,使用 Google Play 结算库中的 BillingClient.acknowledgePurchase() 确认订阅。所有初始订阅购买交易都需要确认。续订购买交易不需要确认。如需详细了解订阅何时需要确认,请参阅销售订阅内容主题。
回顾
以下代码段简要介绍了这些步骤。
Kotlin
fun handlePurchase(Purchase purchase) { // Purchase retrieved from BillingClient#queryPurchasesAsync or your // onPurchasesUpdated. Purchase purchase = ...; // Step 1: Send the purchase to your secure backend to verify the purchase // following // https://developer.android.com/google/play/billing/security#verify . // Step 2: Update your entitlement storage with the purchase. If purchase is // in PENDING state then ensure the entitlement is marked as pending and the // user does not receive benefits yet. It is recommended that this step is // done on your secure backend and can combine in the API call to your // backend in step 1. // Step 3: Notify the user using appropriate messaging (delaying // notification if needed as discussed above). // Step 4: Notify Google the purchase was processed using the steps // discussed in the processing purchases section. }
Java
void handlePurchase(Purchase purchase) { // Purchase retrieved from BillingClient#queryPurchasesAsync or your // onPurchasesUpdated. Purchase purchase = ...; // Step 1: Send the purchase to your secure backend to verify the purchase // following // https://developer.android.com/google/play/billing/security#verify // Step 2: Update your entitlement storage with the purchase. If purchase is // in PENDING state then ensure the entitlement is marked as pending and the // user does not receive benefits yet. It is recommended that this step is // done on your secure backend and can combine in the API call to your // backend in step 1. // Step 3: Notify the user using appropriate messaging (delaying // notification if needed as discussed above). // Step 4: Notify Google the purchase was processed using the steps // discussed in the processing purchases section. }
如需验证您的应用是否已正确实现这些步骤,您可以按照测试指南操作。
处理待处理的交易
Google Play 支持待处理的交易,即从用户发起购买交易到购买交易的付款方式得到处理期间需要执行一个或多个额外步骤的交易。在 Google 通知您已通过用户的付款方式成功扣款之前,您的应用不得授予对这些类型的购买交易的权利。
例如,用户可以选择一家实体店,以便稍后使用现金付款,从而发起交易。用户会通过通知和电子邮件收到一个代码。当用户到达实体店时,可以在收银员处兑换该代码并用现金支付。Google 随后会通知您和用户付款已收到。您的应用随后就可以授予用户权利了。
在初始化 BillingClient 的过程中调用 enablePendingPurchases(),以针对应用启用待处理的交易。应用必须针对一次性商品启用并支持待处理的交易。在添加支持之前,请务必了解待处理交易的购买生命周期。
当应用通过 PurchasesUpdatedListener 或由于调用 queryPurchasesAsync 而收到新的购买交易时,使用 getPurchaseState() 方法确定购买交易的状态是 PURCHASED 还是 PENDING。只有在状态为 PURCHASED 时,您才能授予使用权。
如果您的应用在用户完成购买交易时正在运行,并且您拥有有效的 Play 结算库连接,系统会再次调用 PurchasesUpdatedListener,并且 PurchaseState 现在为 PURCHASED。此时,您的应用可以使用检测和处理购买交易的标准方法处理购买交易。此外,应用还应在其 onResume() 方法中调用 queryPurchasesAsync(),以处理在应用未运行时已转换为 PURCHASED 状态的购买交易。
当购买交易从 PENDING 过渡到 PURCHASED 时,real_time_developer_notifications 客户端会收到 ONE_TIME_PRODUCT_PURCHASED 或 SUBSCRIPTION_PURCHASED 通知。如果购买交易被取消,您会收到 ONE_TIME_PRODUCT_CANCELED 或 SUBSCRIPTION_PENDING_PURCHASE_CANCELED 通知。如果客户没有在规定的时间范围内完成付款,就会发生这种情况。请注意,您始终可以使用 Google Play Developer API 检查购买交易的当前状态。
处理多件购买交易
Google Play 允许客户在一笔交易中购买多件相同的一次性商品,只需在购物车中指定商品数量即可(4.0 及更高版本的 Google Play 结算库支持该功能)。应用应根据指定的购买数量来处理多件购买交易并授予使用权。
为了实现多件购买,应用的配置逻辑需要检查商品数量。您可以通过以下 API 访问 quantity 字段:
- Google Play 结算库中的
getQuantity()。 - Google Play Developer API 中的
Purchases.products.quantity
添加用于处理多件购买交易的逻辑后,您需要在 Google Play 管理中心的一次性商品管理页面上为相应的商品启用多件购买功能。
查询用户的结算配置
getBillingConfigAsync() 提供用户在 Google Play 中使用的国家/地区设置。
您可以在创建
BillingClient 后查询用户的结算配置。以下代码段说明了如何调用 getBillingConfigAsync()。通过实现 BillingConfigResponseListener 来处理响应。此监听器可接收应用中发起的所有结算配置查询的更新。
如果返回的 BillingResult 不含错误,您可以查看 BillingConfig 对象中的 countryCode 字段,以获取用户的 Play 国家/地区信息。
Kotlin
// Use the default GetBillingConfigParams. val getBillingConfigParams = GetBillingConfigParams.newBuilder().build() billingClient.getBillingConfigAsync(getBillingConfigParams, object : BillingConfigResponseListener { override fun onBillingConfigResponse( billingResult: BillingResult, billingConfig: BillingConfig? ) { if (billingResult.responseCode == BillingResponseCode.OK && billingConfig != null) { val countryCode = billingConfig.countryCode ... } else { // TODO: Handle errors } } })
Java
// Use the default GetBillingConfigParams. GetBillingConfigParams getBillingConfigParams = GetBillingConfigParams.newBuilder().build(); billingClient.getBillingConfigAsync(getBillingConfigParams, new BillingConfigResponseListener() { public void onBillingConfigResponse( BillingResult billingResult, BillingConfig billingConfig) { if (billingResult.getResponseCode() == BillingResponseCode.OK && billingConfig != null) { String countryCode = billingConfig.getCountryCode(); ... } else { // TODO: Handle errors } } });
Google Play Games 主屏幕中的弃购提醒(默认处于启用状态)
对于通过一次性商品创收的游戏开发者,在 Google Play 管理中心内处于有效状态的库存单位 (SKU) 可在您的应用之外销售,方法是使用“弃购提醒”功能,该功能会在用户浏览 Google Play 商店时提醒他们完成之前放弃的购买交易。这些购买交易发生在您的应用之外,即在 Google Play 商店的 Google Play Games 首页中。
此功能默认处于启用状态,可帮助用户从上次中断的地方继续观看,并帮助开发者最大限度地提高销售额。不过,您可以提交“弃购提醒”功能停用表单,为您的应用停用此功能。 如需了解在 Google Play 管理中心内管理 SKU 的最佳实践,请参阅创建应用内商品。
以下图片展示了在 Google Play 商店中显示的购物车遗弃提醒: