本文將詳細說明如何將一次性產品 (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 "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()
方法取得這項資訊。
購買選項和優惠
購買選項可讓您定義授予使用者授權的方式、價格,以及產品可供使用的區域。單一產品可有多個購買選項,可代表你販售產品的地點和方式。
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 用戶端程式庫。
啟動租看選項的購買流程
如要啟動租借商品的購買流程,請按照下列步驟操作:
使用
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(); } } } } } });
啟動結帳系統流程。
如要透過應用程式啟動購買要求,請從應用程式的主要執行緒呼叫
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 整合方面。
啟動預購商品的購買流程
如要啟動預購商品的購買流程,請按照下列步驟操作:
使用
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(); } } } } } });
啟動結帳系統流程。
如要透過應用程式啟動購買要求,請從應用程式的主要執行緒呼叫
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(); // … } } } } });
折扣優惠層級的數量有限
你可以在折扣商品層級指定數量上限,但這項設定只會套用至商品層級。以下提供範例說明:
- Super screensavers 有 2 種螢幕保護程式產品:購買選項螢幕保護程式和折扣螢幕保護程式。
- 購買選項螢幕保護程式未設定數量限制。
- 折扣螢幕保護程式已將商品層級的允許數量上限設為 3。
- 螢幕保護程式產品沒有產品層級的數量上限,因此使用者可以購買無限量的這項產品。
- 使用者擁有 1 個折扣螢幕保護程式,並打算購買另一個含有折扣螢幕保護程式的螢幕保護程式。
- 擷取可用優惠時,購買選項螢幕保護程式的 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 個折扣螢幕保護程式。
使用者購買了折扣螢幕保護程式。如果使用者接著嘗試購買第二個折扣螢幕保護程式,系統會發生錯誤,
PurchasesUpdatedListener
也會收到 ITEM_UNAVAILABLE 回應代碼。使用者要求退還原本購買的折扣螢幕保護程式,並成功收到退款。使用者嘗試購買折扣的螢幕保護程式,購買交易會成功。
適用國家/地區
您可以選擇要向使用者提供購買選項優惠或折扣優惠的國家/地區。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()
方法會傳回 SSProductTag
和 SSPurchaseOptionTag
。對於折扣優惠,方法會傳回 SSProductTag
、SSPurchaseOptionTag
和 SSDiscountOfferTag
。