提醒
1. 从 2023 年 8 月 2 日起,所有新应用都必须使用结算库版本 5 或更高版本。自 2023 年 11 月 1 日起,现有应用的所有新版本都必须使用结算库版本 5 或更高版本。了解详情
2. 如果您的应用以 Android 14 或更高版本为目标平台,您必须更新到 PBL 5.2.1PBL 6.0.1 或更高版本。

备选结算系统的应用内集成指南(仅限韩国)

本指南介绍了如何将备选结算系统 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 alternativeBillingListener =
   AlternativeBillingListener { alternateChoiceDetails ->
       // Handle alternative billing choice.
   }

var billingClient = BillingClient.newBuilder(context)
   .setListener(purchasesUpdatedListener)
   .enablePendingPurchases()
   .enableAlternativeBilling(alternativeBillingListener)
   .build()

Java

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

private AlternativeBillingListener alternativeBillingListener = new AlternativeBillingListener() {
    @Override
    public void userSelectedAlternativeBilling(
        AlternativeChoiceDetails alternateChoiceDetails) {
        // Handle new Google Play purchase.
    }
};

private BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .enableAlternativeBilling(alternativeBillingListener)
    .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 设置期间调用 enableAlternativeBilling 用户看到新的用户体验 用户会看到标准的 Google Play 结算系统用户体验
在 BillingClient 设置期间调用 enableAlternativeBilling 用户会看到标准的 Google Play 结算系统用户体验 用户会看到标准的 Google Play 结算系统用户体验

处理用户选择

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

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

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

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

AlternativeBillingListener 应执行以下操作:

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

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

以下示例演示了如何实现 AlternativeBillingListener

Kotlin

private val alternativeBillingListener =
    AlternativeBillingListener { alternativeChoiceDetails ->
        // Get the products being purchased by the user.
        val products = alternativeChoiceDetails.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(
            alternativeChoiceDetails.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 AlternativeBillingListener alternativeBillingListener = new AlternativeBillingListener() {
    @Override
    public void userSelectedAlternativeBilling(
           AlternativeChoiceDetails alternateChoiceDetails) {
       // Get the products being purchased by the user.
       List<Product> products =
              alternativeChoiceDetails.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(
              alternateChoiceDetails.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。请使用 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 AlternativeBillingListener 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 AlternativeBillingListener is triggered.

在备选结算系统中完成升级或降级后,您需要使用通过之前针对新订阅购买交易的调用所获得的外部交易令牌来报告新交易

通过 Google Play 结算系统购买的订阅

同样,如果用户选择通过 Google Play 结算系统购买其当前订阅,系统应向其显示 Google Play 结算系统中的升级或降级流程。以下说明介绍了如何通过 Google Play 结算系统启动用于实现升级或降级的购买流程:

  1. 为新方案确定所选优惠的 offerToken

    Kotlin

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

    Java

    String offerTokenNewPlan = productDetailsNewPlan
                         .getSubscriptionOfferDetails(selectedOfferIndex)
                         .getOfferToken();
    
  2. 将正确的信息发送到 Google Play 结算系统以处理新的购买交易,包括现有订阅的购买令牌:

    Kotlin

    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)
    

    Java

    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,如启动用户自选结算流程中所述。

后续步骤

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