提供其他結帳系統 (包括使用者自選的其他結帳系統) 的應用程式內整合指南

本指南說明如何整合 API,以便在應用程式中提供可讓使用者自選的其他結帳系統。

Play 帳款服務程式庫設定

將 Play 帳款服務程式庫依附元件新增至您的 Android 應用程式。您需要採用 5.2 以上版本,才能使用其他結帳系統 API。如需從舊版遷移至新版,請先按照遷移指南的指示操作,再嘗試導入其他結帳系統。

連線至 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 結帳系統的使用者體驗,不讓使用者自選結帳系統。
  • 如果使用者的 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 AP,藉此向 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()

測試其他結帳系統

請使用授權測試人員測試其他結帳系統的整合作業。對於授權測試人員帳戶所發起的交易,您不會收到月結單。如要進一步瞭解如何設定授權測試人員,請參閱「使用應用程式授權測試應用程式內結帳」。

後續步驟

完成應用程式內整合作業後,即可開始整合後端