一次性產品的多種購買選項和優惠

本文將詳細說明如何將一次性產品 (OTP) 與 Play 帳款服務程式庫整合。並進一步說明如何整合與一次性產品相關的各種購買選項和優惠。

您可以為一次性產品設定多種購買選項和優惠。舉例來說,您可以為同一個一次性產品設定購買選項和預購商品。

必要條件

如要為一次性消費產品設定多項商品,您必須使用 queryProductDetailsAsync() API。系統不支援已淘汰的 querySkuDetailsAsync() API。如要瞭解如何使用 queryProductDetailsAsync() 和採用 ProductDetailsParams 做為輸入內容的 launchBillingFlow() 版本,請參閱遷移步驟

查詢產品詳細資料

如果您為一次性產品設定多個優惠或購買選項,則 queryProductDetailsAsync() 方法傳回的 ProductDetails 物件,每個一次性產品可提供多個購買和/或租借選項。如要取得每個 ProductDetails 物件適用的所有符合資格優惠清單,請使用 getOneTimePurchaseOfferDetailsList() 方法。這個清單只會傳回使用者符合資格的優惠和購買選項。onProductDetailsResponse() 方法中的程式碼應處理傳回的商品。

啟動結帳系統流程

如要透過應用程式啟動購買要求,請從應用程式的主要執行緒呼叫 launchBillingFlow() 方法。這個方法會參照 BillingFlowParams 物件,該物件包含從呼叫 queryProductDetailsAsync() 取得的相關 ProductDetails 物件。如要建立 BillingFlowParams 物件,請使用 BillingFlowParams.Builder 類別。請注意,您必須在建立 BillingFlowParams 物件時,設定與使用者所選優惠相對應的優惠權杖。

以下範例說明如何針對含有多項商品的一次性產品啟動購買流程:

Java

    
// An activity reference from which the billing flow will launch.
Activity activity = ...;
ImmutableList<ProductDetailsParams> productDetailsParamsList =
    ImmutableList.of(
        ProductDetailsParams.newBuilder()
             // retrieve a value for &quot;productDetails&quot; by calling queryProductDetailsAsync()
            .setProductDetails(productDetails)
            // to get an offer token, call
            // ProductDetails.getOneTimePurchaseOfferDetailsList() 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);
    
    

offerToken 可在 OneTimePurchaseOfferDetails 中找到。向使用者顯示優惠時,請務必使用正確的優惠符記設定帳單流程參數,您可以透過 oneTimePurchaseOfferDetails.getOfferToken() 方法取得這項資訊。

購買選項和優惠

購買選項可讓您定義授予使用者授權的方式、價格,以及產品可供使用的區域。單一產品可有多個購買選項,可代表你販售產品的地點和方式。

Google Play 支援以下一次性產品的購買選項:

  • 購買選項
  • 租借購買選項

優惠是指您為一次性產品建立的定價方案。舉例來說,您可以為一次性產品建立折扣優惠。

Google Play 支援以下一次性產品的購買優惠:

  • 預購優惠 (僅適用於「購買」購買選項)
  • 折扣優惠 (適用於購買和租借兩種購買選項)

購買選項

購買購買選項代表一次性產品的標準、直接購買交易。這個屬性包含選用的 legacyCompatible 欄位,用於指出這項購買選項是否可在舊版 Play 帳款服務程式庫 (7 以下版本) 流程中使用,因為舊版不支援新模型。為確保回溯相容性,至少應將一個購買選項標示為與舊版相容。

將購買和租看選項與 PBL 整合的步驟相同。如要瞭解如何將購買選項與 PBL 整合,請參閱「將租片選項與 PBL 整合」。

租借購買選項

租賃購買選項可讓使用者在特定時間內存取一次性產品。您可以指定租借期和到期時間。本文說明將租片購買選項與 Play 帳款服務程式庫 (PBL) 整合的步驟。

將租片購買選項與 PBL 整合

本節說明如何將租片購買選項與 Play 帳款服務程式庫 (PBL) 整合。這篇文章假設您熟悉初始的 PBL 整合步驟,例如將 PBL 依附元件新增至應用程式、初始化 BillingClient連線至 Google Play。本節將著重於租借購買選項的特定 PBL 整合方式。

如要設定可供租借的產品,您必須使用 Play Developer API 或 Play 管理中心 UI 的新 monetization.onetimeproducts 服務。如要使用這項服務,您可以直接呼叫 REST API,或使用 Java 用戶端程式庫

啟動租看選項的購買流程

如要啟動租借商品的購買流程,請按照下列步驟操作:

  1. 使用 ProductDetails.oneTimePurchaseOfferDetails.getRentalDetails() 方法擷取租片購買選項中繼資料。

    以下範例說明如何取得租片購買交易的中繼資料:

    Java

    billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
      public void onProductDetailsResponse(
          BillingResult billingResult, QueryProductDetailsResult productDetailsResult) {
        // check billingResult
        // …
        // process productDetailsList returned by QueryProductDetailsResult
        for (ProductDetails productDetails : productDetailsResult.getProductDetailsList()) {
          for (OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails :
              productDetails.getOneTimePurchaseOfferDetailsList()) {
            // Checks if the offer is a rent purchase option.
            if (oneTimePurchaseOfferDetails.getRentalDetails() != null) {
              // process the returned RentalDetails
              OneTimePurchaseOfferDetails.RentalDetails rentalDetails =
                  oneTimePurchaseOfferDetails.getRentalDetails();
              // Get rental period in ISO 8601 format.
              String rentalPeriod = rentalDetails.getRentalPeriod();
              // Get rental expiration period in ISO 8601 format, if present.
              if (rentalDetails.getRentalExpirationPeriod() != null) {
                String rentalExpirationPeriod = rentalDetails.getRentalExpirationPeriod();
              }
              // Get offer token
                String offerToken = oneTimePurchaseOfferDetails.getOfferToken();
              // Get the associated purchase option ID
              if (oneTimePurchaseOfferDetails.getPurchaseOptionId() != null) {
                String purchaseOptionId = oneTimePurchaseOfferDetails.getPurchaseOptionId();
              }
            }
          }
        }
      }
    });
  2. 啟動結帳系統流程。

    如要透過應用程式啟動購買要求,請從應用程式的主要執行緒呼叫 launchBillingFlow() 方法。這個方法會參照 BillingFlowParams 物件,該物件包含從呼叫 queryProductDetailsAsync() 取得的相關 ProductDetails 物件。如要建立 BillingFlowParams 物件,請使用 BillingFlowParams.Builder 類別。請注意,建立 BillingFlowParams 物件時,您必須設定與使用者所選優惠相對應的優惠權杖。如果使用者符合租片購買選項的資格,系統會在 queryProductDetailsAsync() 中提供含有 RentalDetails 和 offerId 的商品。

    以下範例說明如何啟動帳單流程:

    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);

    offerToken 可在 OneTimePurchaseOfferDetails 中找到。向使用者顯示優惠時,請務必使用正確的優惠權杖設定帳單流程參數,您可以透過 oneTimePurchaseOfferDetails.getOfferToken() 方法取得這項權杖。

預購優惠

預購功能可讓你設定一次性產品,讓消費者在產品發售前購買。使用者預購產品時,除非在發售日期前取消預購,否則他們同意在產品發售時支付商品費用。在發布日期當天,系統會向買家收費,並透過電子郵件通知他們商品已發布。

本文說明如何將預購購買商品與 Play 帳款服務程式庫 (PBL) 整合。

將預購優惠與 PBL 整合

本節說明如何將預購商品與 Play 帳款服務程式庫 (PBL) 整合。這篇文章假設您熟悉初始的 PBL 整合步驟,例如將 PBL 依附元件新增至應用程式、初始化 BillingClient連線至 Google Play。本節將著重於預購優惠的 PBL 整合方面。

啟動預購商品的購買流程

如要啟動預購商品的購買流程,請按照下列步驟操作:

  1. 使用 ProductDetails.oneTimePurchaseOfferDetails.getPreorderDetails() 方法擷取預購商品中繼資料。以下範例說明如何取得預購商品中繼資料:

    Java

    billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
      public void onProductDetailsResponse(
          BillingResult billingResult, QueryProductDetailsResult productDetailsResult) {
        // check billingResult
        // …
        // process productDetailsList returned by QueryProductDetailsResult
        for (ProductDetails productDetails : productDetailsResult.getProductDetailsList()) {
          for (OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails :
              productDetails.getOneTimePurchaseOfferDetailsList()) {
            // Checks if the offer is a preorder offer.
            if (oneTimePurchaseOfferDetails.getPreorderDetails() != null) {
              // process the returned PreorderDetails
              OneTimePurchaseOfferDetails.PreorderDetails preorderDetails =
                  oneTimePurchaseOfferDetails.getPreorderDetails();
              // Get preorder release time in millis.
              long preorderReleaseTimeMillis = preorderDetails.getPreorderReleaseTimeMillis();
              // Get preorder presale end time in millis.
              long preorderPresaleEndTimeMillis = preorderDetails.getPreorderPresaleEndTimeMillis();
              // Get offer ID
                String offerId = oneTimePurchaseOfferDetails.getOfferId();
              // Get the associated purchase option ID
              if (oneTimePurchaseOfferDetails.getPurchaseOptionId() != null) {
                String purchaseOptionId = oneTimePurchaseOfferDetails.getPurchaseOptionId();
              }
            }
          }
        }
      }
    });

  2. 啟動結帳系統流程。

    如要透過應用程式啟動購買要求,請從應用程式的主要執行緒呼叫 launchBillingFlow() 方法。這個方法會參照 BillingFlowParams 物件,其中包含藉由呼叫 queryProductDetailsAsync() 取得的相關 ProductDetails 物件。如要建立 BillingFlowParams 物件,請使用 BillingFlowParams.Builder class。請注意,您必須設定與使用者所選優惠相對應的優惠權杖,才能建立 BillingFlowParams 物件。如果使用者符合預購優惠的資格,系統會在 queryProductDetailsAsync() 方法中提供含有 PreorderDetails 和 offerId 的優惠。

    以下範例說明如何啟動帳單流程:

    Java

    // An activity reference from which the billing flow will launch.
    Activity activity = ...;
    ImmutableList productDetailsParamsList =
        ImmutableList.of(
        ProductDetailsParams.newBuilder()
             // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
            .setProductDetails(productDetails)
            // to get an offer token, call
            // ProductDetails.getOneTimePurchaseOfferDetailsList() 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);

    offerToken 可在 OneTimePurchaseOfferDetails 中找到。向使用者顯示優惠時,請務必使用正確的優惠權杖設定帳單流程參數,您可以透過 oneTimePurchaseOfferDetails.getOfferToken() 方法取得這項權杖。

折扣優惠

本節說明如何為一次性產品設定折扣優惠。

一次性產品折扣優惠有四個不同的參數可供設定:

  • 折扣優惠價格:指定折扣百分比或原價的絕對折扣價格。

  • 適用國家/地區:指定一次性產品優惠在國家/地區的供應情形。

  • 購買次數上限 (選用):讓您決定使用者可兌換相同優惠的次數。如果使用者購買的商品數量超過上限,就無法獲得優惠。

  • 限時優惠 (選用):指定優惠適用的時間範圍。在時間範圍以外,使用者就無法購買該優惠。

擷取折扣優惠價格資訊

對於折扣優惠,您可以擷取折扣百分比或提供的絕對折扣。

範例 1:擷取折扣商品的折扣百分比

以下範例說明如何取得折扣優惠的原始全價和折扣百分比。請注意,系統只會針對折扣商品傳回百分比折扣資訊。

Java

billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
      public void onProductDetailsResponse(
          BillingResult billingResult, QueryProductDetailsResult productDetailsResult){
        // check billingResult
        // …
        // process productDetailsList returned by QueryProductDetailsResult
        for (ProductDetails productDetails : productDetailsResult.getProductDetailsList()) {
          for (OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails :
              productDetails.getOneTimePurchaseOfferDetailsList()) {
            long discountedOfferPriceMicros =
                oneTimePurchaseOfferDetails.getPriceAmountMicros();
            // process the returned fullPriceMicros and percentageDiscount.
            if (oneTimePurchaseOfferDetails.getFullPriceMicros() != null) {
              long fullPriceMicros = oneTimePurchaseOfferDetails.getFullPriceMicros();
            }
            if (oneTimePurchaseOfferDetails.getDiscountDisplayInfo() != null) {
              long percentageDiscount =
                  oneTimePurchaseOfferDetails
                      .getDiscountDisplayInfo()
                      .getPercentageDiscount();
            }
            // …
          }
        }
      }
    });
    
範例 2:擷取折扣商品的絕對折扣

以下範例說明如何取得折扣商品的原始全價和絕對折扣值 (以微秒為單位)。請注意,微服務資訊中的絕對折扣只會針對已折扣的商品傳回。折扣優惠必須指定絕對折扣或百分比折扣。

Java

billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
      public void onProductDetailsResponse(
          BillingResult billingResult, QueryProductDetailsResult productDetailsResult) {
        // check billingResult
        // …
        // process productDetailsList returned by QueryProductDetailsResult
        for (ProductDetails productDetails : productDetailsResult.getProductDetailsList()) {
          for (OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails :
              productDetails.getOneTimePurchaseOfferDetailsList()) {
            long discountedOfferPriceMicros =
                oneTimePurchaseOfferDetails.getPriceAmountMicros();
            // process the returned fullPriceMicros and absolute DiscountAmountMicros.
            if (oneTimePurchaseOfferDetails.getFullPriceMicros() != null) {
              long fullPriceMicros = oneTimePurchaseOfferDetails.getFullPriceMicros();
            }
            if (oneTimePurchaseOfferDetails.getDiscountDisplayInfo() != null) {
              long discountAmountMicros =
                  oneTimePurchaseOfferDetails
                      .getDiscountDisplayInfo()
                      .getDiscountAmount()
                      .getDiscountAmountMicros();
            }
            // …
          }
        }
      }
    });
    

取得優惠的有效時間範圍

您可以使用 OneTimePurchaseOfferDetails.getValidTimeWindow() 方法,取得商品的有效時間範圍。這個物件包含時間區間的開始和結束時間 (以毫秒為單位)。

以下範例說明如何取得商品有效時間範圍:

Java

billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
      public void onProductDetailsResponse(
          BillingResult billingResult, QueryProductDetailsResult productDetailsResult) {
        // check billingResult
        // …
        // process productDetailsList returned by QueryProductDetailsResult
        for (ProductDetails productDetails : productDetailsResult.getProductDetailsList()) {
          for (OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails :
              productDetails.getOneTimePurchaseOfferDetailsList()) {
            if (oneTimePurchaseOfferDetails.getValidTimeWindow() != null) {
              // process the returned startTimeMillis and endTimeMillis.
              ValidTimeWindow validTimeWindow =
                  oneTimePurchaseOfferDetails.getValidTimeWindow();
              long startTimeMillis = validTimeWindow.getStartTimeMillis();
              long endTimeMillis = validTimeWindow.getEndTimeMillis();
              // …
            }
          }
        }
      }
    });
    

折扣優惠層級的數量有限

你可以在折扣商品層級指定數量上限,但這項設定只會套用至商品層級。以下提供範例說明:

  1. Super screensavers 有 2 種螢幕保護程式產品:購買選項螢幕保護程式和折扣螢幕保護程式。
    1. 購買選項螢幕保護程式未設定數量限制。
    2. 折扣螢幕保護程式已將商品層級的允許數量上限設為 3。
  2. 螢幕保護程式產品沒有產品層級的數量上限,因此使用者可以購買無限量的這項產品。
  3. 使用者擁有 1 個折扣螢幕保護程式,並打算購買另一個含有折扣螢幕保護程式的螢幕保護程式。
  4. 擷取可用優惠時,購買選項螢幕保護程式的 LimitedQuantityInfo 為空值,而折扣螢幕保護程式的剩餘數量值為 2。

以下範例說明如何取得折扣優惠層級的限量數量:

Java

billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
      public void onProductDetailsResponse(
          BillingResult billingResult, QueryProductDetailsResult productDetailsResult) {
        // check billingResult
        // …
        // process productDetailsList returned by QueryProductDetailsResult
        for (ProductDetails productDetails : productDetailsResult.getProductDetailsList()) {
          for (OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails :
              productDetails.getOneTimePurchaseOfferDetailsList()) {
            if (oneTimePurchaseOfferDetails.getLimitedQuantityInfo() != null) {
              // process the returned maximumQuantity and remainingQuantity.
              LimitedQuantityInfo limitedQuantityInfo =
                  oneTimePurchaseOfferDetails.getLimitedQuantityInfo();
              int maximumQuantity = limitedQuantityInfo.getMaximumQuantity();
              int remainingQuantity = limitedQuantityInfo.getRemainingQuantity();
              // …
            }
          }
        }
      }
    });
    

當使用者兌換的優惠數量達到上限時,getOneTimePurchaseOfferDetailsList() 方法就不會傳回優惠。

計算兌換上限

以下範例說明如何取得特定折扣優惠的限量資訊。您可以取得目前使用者的允許數量上限和剩餘數量。請注意,數量有限功能適用於消耗性和非消耗性一次性產品。這項功能僅適用於商品層級。

Google Play 會將使用者擁有的數量從您設定的允許上限中扣除,計算剩餘數量。在計算使用者擁有的數量時,Google Play 會考量已消費的購買交易或待處理的購買交易。已取消、退款或退費的購買交易不會計入使用者擁有的數量。例如:

  1. 超級螢幕保護程式會設定折扣優惠,允許購買的數量上限為 1,因此使用者最多只能購買 1 個折扣螢幕保護程式。

  2. 使用者購買了折扣螢幕保護程式。如果使用者接著嘗試購買第二個折扣螢幕保護程式,系統會發生錯誤,PurchasesUpdatedListener 也會收到 ITEM_UNAVAILABLE 回應代碼。

  3. 使用者要求退還原本購買的折扣螢幕保護程式,並成功收到退款。使用者嘗試購買折扣的螢幕保護程式,購買交易會成功。

適用國家/地區

您可以選擇要向使用者提供購買選項優惠或折扣優惠的國家/地區。Google Play 會根據 Play 國家/地區來評估使用者是否符合資格。設定商品的區域供應情形時,只有在使用者位於指定國家/地區時,系統才會將商品列入 getOneTimePurchaseOfferDetailsList() 的一部分,否則不會列入呼叫 queryProductDetailsAsync() 時傳回的商品清單。

優惠代碼

以下範例說明如何擷取與商品相關聯的商品標記。

Java

    
billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
      public void onProductDetailsResponse(
          BillingResult billingResult, QueryProductDetailsResult productDetailsResult) {
        // check billingResult
        // …
        // process productDetailsList returned by QueryProductDetailsResult
        for (ProductDetails productDetails : productDetailsResult.getProductDetailsList()) {
          for (OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails :
              productDetails.getOneTimePurchaseOfferDetailsList()) {
            // process the returned offer tags.
            ImmutableList<String> offerTags =
                oneTimePurchaseOfferDetails.getOfferTagsList();
            // …
          }
        }
      }
    });
    
    

優惠代碼的繼承

你可以為產品、購買選項或折扣優惠設定商品標記。折扣優惠會繼承購買選項優惠的商品標記。同樣地,如果在產品層級指定商品代碼,購買選項商品和折扣商品都會繼承產品商品代碼。

舉例來說,Super 螢幕保護程式有兩種螢幕保護程式產品:購買選項螢幕保護程式和折扣螢幕保護程式。

  • Super 螢幕保護程式含有產品優惠代碼 SSProductTag
  • 購買選項畫面保護程式包含優惠代碼 SSPurchaseOptionTag
  • 折扣螢幕保護程式含有優惠代碼 SSDiscountOfferTag

在這個範例中,購買選項商品的 oneTimePurchaseOfferDetails.getOfferTagsList() 方法會傳回 SSProductTagSSPurchaseOptionTag。對於折扣優惠,方法會傳回 SSProductTagSSPurchaseOptionTagSSDiscountOfferTag