包含用户选择功能的替代计费的应用内集成指南

本指南介绍了如何集成 API 以在您的应用中提供包含用户选择功能的替代计费。

Play 计费库设置

将 Play 计费库依赖项 添加到您的 Android 应用中。要使用替代计费 API,您需要使用 5.2 版或更高版本。如果您需要从早期版本迁移,请在尝试实施替代计费之前,按照 迁移指南 中的说明操作。

连接到 Google Play

集成过程中的第一步与 Google Play 计费集成指南 中描述的步骤相同,在 初始化 BillingClient 时有一些修改。

以下示例演示了如何使用这些修改初始化 BillingClient

Kotlin

val purchasesUpdatedListener =
   PurchasesUpdatedListener { billingResult, purchases ->
       // Handle new Google Play purchase.
   }

val userChoiceBillingListener =
   UserChoiceBillingListener { userChoiceDetails ->
       // Handle alternative billing choice.
   }

var billingClient = BillingClient.newBuilder(context)
   .setListener(purchasesUpdatedListener)
   .enablePendingPurchases()
   .enableUserChoiceBilling(userChoiceBillingListener)
   .build()

Java

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        // Handle new Google Play purchase.
    }
};

private UserChoiceBillingListener userChoiceBillingListener = new UserChoiceBillingListener() {
    @Override
    public void userSelectedAlternativeBilling(
        UserChoiceDetails userChoiceDetails) {
        // Handle new Google Play purchase.
    }
};

private BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .enableUserChoiceBilling(userChoiceBillingListener)
    .build();

初始化 BillingClient 后,您需要按照集成指南中所述 建立与 Google Play 的连接

显示可用产品

您可以 以与 Google Play 计费系统集成相同的方式向用户显示可用产品。当用户查看了可购买的产品并选择了一个要购买的产品时,请按照以下部分中的说明启动用户选择计费流程。

启动用户选择计费流程

通过调用 launchBillingFlow() 启动用户选择计费流程。这与使用 Google Play 计费系统集成 启动购买流程 的方式相同:您提供一个 ProductDetails 实例和一个 offerToken,分别对应用户想要获取的产品和优惠。如果用户选择 Google Play 的计费系统,则使用此信息继续购买流程。

当开发者调用 launchBillingFlow() 时,Google Play 计费系统会执行以下检查

  • 系统会检查用户的 Google Play 国家/地区 是否支持使用用户选择的替代计费(即受支持的国家/地区)。如果用户的 Google Play 国家/地区受支持,则 Google Play 会根据 BillingClient 的配置检查是否已启用替代计费。
    • 如果已启用使用用户选择的替代计费,则购买流程会显示 用户选择 UX
    • 如果**未**启用使用用户选择的替代计费,则购买流程会显示标准的 Google Play 计费系统 UX,不提供用户选择。
  • 如果用户的 Google Play 国家/地区**不是**受支持的国家/地区,则购买流程会显示标准的 Google Play 计费系统 UX,不提供用户选择。

用户的 Play 国家/地区是受支持的国家/地区

用户的 Play 国家/地区不是受支持的国家/地区

在 BillingClient 设置期间调用 enableUserChoiceBilling

用户看到用户选择 UX

用户看到标准的 Google Play 计费系统 UX

在 BillingClient 设置期间未调用 enableUserChoiceBilling

用户看到标准的 Google Play 计费系统 UX

用户看到标准的 Google Play 计费系统 UX

处理用户选择

您处理购买流程其余部分的方式取决于用户选择的是 Google Play 的计费系统还是替代计费系统。

当用户选择替代计费系统时

如果用户选择替代计费系统,Google Play 会调用 UserChoiceBillingListener 通知应用需要在替代计费系统中启动购买流程。特别是,会调用 userSelectedAlternativeBilling() 方法。

UserChoiceDetails 对象中提供的外部交易令牌代表用户选择进入替代计费流程的签名。请使用此令牌报告由此选择产生的任何交易,如 后端集成指南 中所述。

UserChoiceBillingListener 应执行以下操作

  • 获取用户正在购买的产品,以便可以在替代计费系统的购买流程中显示这些产品。
  • 收集作为外部交易令牌接收的字符串并将其发送到您的后端以持久保存。如果用户完成此特定购买,则稍后会使用此令牌向 Google Play 报告外部交易。
  • 启动开发者的替代购买流程。

如果用户使用替代计费系统完成购买,**您必须在 24 小时内通过从您的后端调用 Google Play 开发者 API 向 Google Play 报告交易**,并提供 externalTransactionToken 和其他交易详细信息。有关更多详细信息,请参阅 后端集成指南

以下示例演示如何实现 UserChoiceBillingListener

Kotlin

private val userChoiceBillingListener =
    UserChoiceBillingListener { userChoiceDetails ->
        // Get the products being purchased by the user.
        val products = userChoiceDetails.products

        // Send external transaction token to developer backend server
        // this devBackend object is for demonstration purposes,
        // developers can implement this step however best fits their
        // app to backend communication.
        devBackend.sendExternalTransactionStarted(
            userChoiceDetails.externalTransactionToken,
            user
        )

        // Launch alternative billing
        // ...
        // The developer backend handles reporting the transaction
        // to Google Play's backend once the alternative billing
        // purchase is completed.
    }

Java

private userChoiceBillingListener userChoiceBillingListener = new UserChoiceBillingListener() {
    @Override
    public void userSelectedAlternativeBilling(
           UserChoiceDetails userChoiceDetails) {
       // Get the products being purchased by the user.
       List<Product> products =
              userChoiceDetails.getProducts();

       // Send external transaction token to developer backend server
       // this devBackend object is for demonstration purposes,
       // developers can implement this step however best fits their
       // app to backend communication.
       devBackend.sendExternalTransactionStarted(
              userChoiceDetails.getExternalTransactionToken(),
              user
       );

       // Launch alternative billing
       // ...
       // The developer backend handles reporting the transaction
       // to Google Play's backend once the alternative billing
       // purchase is completed.
    }
};

当用户选择 Google Play 的计费系统时

如果用户选择 Google Play 的计费系统,他们将通过 Google Play 继续购买。

  • 有关如何通过 Google Play 的计费系统处理新的应用内购买的更多信息,请参阅库集成指南中的 处理购买
  • 有关订阅购买的更多指导,请参阅订阅管理指南中的 新订阅

处理订阅更改

对于使用用户选择的替代计费的开发者,购买需要通过 Google Play 的计费系统处理或使用 externalTransactionId 报告,具体取决于用户的选择。对通过用户选择流程处理的现有订阅所做的更改可以通过相同的计费系统进行,直到订阅到期。

本节介绍如何处理一些常见的订阅更改场景。

升级和降级流程

订阅计划更改(包括升级和降级流程)的处理方式应有所不同,具体取决于订阅最初是通过 Google Play 的计费系统还是通过替代计费系统购买的。

依赖于现有订阅、共享相同付款方式并使循环收费保持一致的附加组件将被视为升级。对于其他附加组件,用户应该能够选择他们想要使用的计费系统。通过使用 launchBillingFlow() 启动新的购买体验,如 启动用户选择计费流程 中所述。

通过替代计费系统购买的订阅

对于用户选择后最初通过开发者替代计费系统购买的订阅,请求升级或降级的用户应通过开发者的替代计费系统继续进行,而无需再次经历用户选择体验。

为此,当用户请求升级或降级时,请调用 launchBillingFlow()。在参数中,不要指定 SubscriptionUpdateParams 对象,而是使用 setOriginalExternalTransactionId,提供原始购买的外部交易 ID。由于原始购买的用户选择会保留以供升级和降级使用,因此**不会**显示用户选择屏幕。在这种情况下,对 launchBillingFlow() 的调用会为交易生成**新的外部交易令牌**,您可以从回调中检索该令牌。

Kotlin

// The external transaction ID from the current
// alternative billing subscription.
val externalTransactionId = //... ;

val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(
        listOf(
            BillingFlowParams.ProductDetailsParams.newBuilder()
                // Fetched via queryProductDetailsAsync.
                .setProductDetails(productDetailsNewPlan)
                // offerIdToken can be found in
                // ProductDetails=>SubscriptionOfferDetails.
                .setOfferToken(offerTokenNewPlan)
                .build()
        )
    )
    .setSubscriptionUpdateParams(
        BillingFlowParams.SubscriptionUpdateParams.newBuilder()
            .setOriginalExternalTransactionId(externalTransactionId)
            .build()

val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

// When the user selects the alternative billing flow,
// the UserChoiceBillingListener is triggered.

Java

// The external transaction ID from the current
// alternative billing subscription.
String externalTransactionId = //... ;

BillingFlowParams billingFlowParams =
        BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(
                ImmutableList.of(
                    ProductDetailsParams.newBuilder()
                        // Fetched via queryProductDetailsAsync.
                        .setProductDetails(productDetailsNewPlan)
                        // offerIdToken can be found in
                        // ProductDetails=>SubscriptionOfferDetails
                        .setOfferToken(offerTokenNewPlan)
                    .build()
                )
            )
            .setSubscriptionUpdateParams(
                SubscriptionUpdateParams.newBuilder()
                    .setOriginalExternalTransactionId(externalTransactionId)
                    .build()
            )
            .build();

BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

// When the user selects the alternative billing flow,
// the UserChoiceBillingListener is triggered.

在替代计费系统中完成升级或降级后,您需要使用通过先前调用为新的订阅购买获得的外部交易令牌 报告新交易

通过 Google Play 的计费系统购买的订阅

同样,在用户选择后通过 Google Play 的计费系统购买了当前订阅的用户应该会看到 Google Play 的计费系统中的 升级或降级流程。以下说明介绍了如何通过 Google Play 的计费系统启动购买流程以进行升级或降级

  1. 确定所选优惠的新计划的 offerToken

val offerTokenNewPlan = productDetailsNewPlan
             .getSubscriptionOfferDetails(selectedOfferIndex)
             .getOfferToken()

String offerTokenNewPlan = productDetailsNewPlan
                     .getSubscriptionOfferDetails(selectedOfferIndex)
                     .getOfferToken();

  1. 将正确的通知发送到 Google Play 的计费系统以处理新的购买,包括现有订阅的购买令牌

val billingFlowParams =
    BillingFlowParams.newBuilder().setProductDetailsParamsList(
        listOf(
            BillingFlowParams.ProductDetailsParams.newBuilder()
                .setProductDetails(productDetailsNewPlan)
                .setOfferToken(offerTokenNewPlan)
                .build()
        )
    )
    .setSubscriptionUpdateParams(
        BillingFlowParams.SubscriptionUpdateParams.newBuilder()
            .setOldPurchaseToken(oldToken)
            .setReplaceProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE)
            .build()
        )
        .build()

BillingClient.launchBillingFlow(activity, billingFlowParams)

BillingFlowParams billingFlowParams =
        BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(
                ImmutableList.of(
                    ProductDetailsParams.newBuilder()
                        // Fetched via queryProductDetailsAsync
                        .setProductDetails(productDetailsNewPlan)
                        // offerIdToken can be found in
                        // ProductDetails=>SubscriptionOfferDetails.
                        .setOfferToken(offerTokenNewPlan)
                        .build()
                )
            )
            .setSubscriptionUpdateParams(
                SubscriptionUpdateParams.newBuilder()
                    // purchaseToken can be found in
                    // Purchase#getPurchaseToken
                    .setOldPurchaseToken("old_purchase_token")
                    .setReplaceProrationMode(ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE)
                    .build()
            )
            .build();

BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

此购买将在 Google Play 的计费系统中进行,您的应用会收到 PurchasesUpdatedListener.onPurchaseUpdated 调用以及购买结果。如果购买成功,则 onPurchaseUpdated() 方法还会接收新的购买信息,并且您的后端会收到 SUBSCRIPTION_PURCHASED 实时开发者通知。在提取新购买的状态时,linkedPurchaseToken 属性会链接到旧的订阅购买,以便您可以 按照建议将其停用。

订阅取消和恢复

用户应该能够随时 取消 他们的订阅。当用户取消订阅时,权限的终止可能会延迟到付费期结束。例如,如果用户在月中取消月度订阅,他们可能会继续访问该服务,直到其访问权限被移除,剩余约 2 周时间。在此期间,订阅在技术上仍然处于活动状态,因此用户可以使用该服务。

用户在此活动期间决定撤消取消的情况并不少见。在本指南中,这称为恢复。以下部分介绍如何在您的替代计费 API 集成中处理恢复场景。

通过替代计费系统购买的订阅

如果您有已取消订阅的外部交易 ID,则无需调用 launchBillingFlow() 来恢复订阅,因此不应将其用于此类型的激活。如果用户在已取消订阅的活动期内恢复其订阅,则此时不会发生任何交易;当当前周期到期并发生下一次续订时,您可以继续报告续订。这包括用户作为恢复的一部分收到信用或特殊续订价格的情况(例如,鼓励用户继续订阅的促销活动)。

通过 Google Play 的计费系统购买的订阅

通常,用户可以在 Google Play 的计费系统中恢复订阅。对于最初在 Google Play 的计费系统上购买的已取消订阅,用户可以通过 Google Play 的 重新订阅 功能在订阅处于活动状态时选择撤消取消。在这种情况下,您的后端会收到 SUBSCRIPTION_RESTARTED 实时开发者通知,并且**不会**发出新的购买令牌,原始令牌将用于继续订阅。要了解如何在 Google Play 的计费系统中管理恢复,请参阅订阅管理指南中的 恢复

您还可以通过调用 launchBillingFlow() 从应用中触发 Google Play 计费系统中的恢复。有关如何执行此操作的说明,请参阅 订阅到期前 - 应用内。对于在原始购买中经历了用户选择流程的用户(该流程已被取消但仍处于活动状态),系统会自动检测其选择并显示用于恢复这些购买的用户界面。系统会要求他们确认通过 Google Play 重新购买订阅,但他们无需再次经历用户选择流程。在这种情况下,会为用户发出新的购买令牌。您的后端会收到 SUBSCRIPTION_PURCHASED 实时开发者通知,并且新购买状态的 linkedPurchaseToken 值与升级或降级的情况一样,设置为已取消订阅的旧购买令牌。

重新订阅

如果订阅完全到期,无论是由于取消还是付款失败且未恢复(已过期的帐户保留),则如果用户想要重新开始权限,则必须重新订阅

也可以通过应用启用重新订阅,方法是将其处理为标准注册。用户应该能够选择他们想要使用的计费系统。在这种情况下,可以调用 launchBillingFlow(),如 启动用户选择计费流程 中所述。

测试替代计费

应使用许可证测试人员来测试您的替代计费集成。您不会因许可证测试人员帐户发起的交易而被开具发票。有关配置许可证测试人员的更多信息,请参阅 使用应用许可测试应用内结算

后续步骤

完成应用内集成后,您就可以 集成您的后端 了。