供用户自选的其他结算方式的应用内集成指南

本指南介绍了如何集成相关 API,以便在应用中提供需用户自选的其他结算方式。

Play 结算库设置

向您的 Android 应用添加 Play 结算库依赖项。如需使用备选结算系统 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 的配置检查是否已启用备选结算系统。
    • 如果已启用需用户自选的其他结算方式,购买流程会显示用户选择体验
    • 如果启用需用户自选的其他结算方式,购买流程会显示标准的 Google Play 结算系统用户体验,无需用户自选。
  • 如果用户的 Google Play 国家/地区不是受支持的国家/地区,购买流程会显示标准的 Google Play 结算系统用户体验,无需用户选择。

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

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

在 BillingClient 设置期间调用 enableUserChoiceBilling

用户会看到用户选择体验

用户会看到标准的 Google Play 结算系统用户体验

在 BillingClient 设置期间未调用 enableUserChoiceBilling

用户会看到标准的 Google Play 结算系统用户体验

用户会看到标准的 Google Play 结算系统用户体验

处理用户选择

购买流程其余部分的处理方式不尽相同,具体取决于用户选择的是 Google Play 结算系统还是一种备选结算系统。

当用户选择备选结算系统时

如果用户选择备选结算系统,Google Play 会调用 UserChoiceBillingListener 来通知应用需在备选结算系统中启动购买流程。具体而言,系统会调用 userSelectedAlternativeBilling() 方法。

UserChoiceDetails 对象中提供的外部交易令牌表示用户选择进入备选结算流程时提供的签名。如后端集成指南中所述,使用此令牌可报告这一选择产生的任何交易。

UserChoiceBillingListener 应执行以下操作:

  • 获取用户要购买的一件或多件商品的数据,以便在备选结算系统的购买流程中展示。
  • 收集接收到的作为外部交易令牌的字符串,并将其发送到后端予以保留。如果用户完成此特定购买交易,此字符串之后会被用于向 Google Play 报告外部交易信息。
  • 启动开发者的备选购买流程。

如果用户使用备选结算系统完成购买交易,您必须在 24 小时内从后端调用 Google Play Developer API 并提供 externalTransactionToken 以及其他交易详情,向 Google Play 报告此交易。如需了解详情,请参阅后端集成指南

以下示例演示了如何实现 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()。请使用 setOriginalExternalTransactionId 提供原始购买交易的外部交易 ID,而不是在参数中指定 SubscriptionUpdateParams 对象。采用这种方式不会显示用户选择界面,因为系统会保留原始购买交易的相关用户选择以用于升级和降级。在此使用场景中,调用 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(),如启动用户自选结算流程中所述。

测试备选结算系统

应使用许可测试人员来测试您的备选结算系统集成。我们不会为许可测试人员帐号发起的交易开具账单。如需详细了解如何配置许可测试人员,请参阅使用应用许可来测试应用内购结算功能

后续步骤

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