本文將詳細說明如何將一次性產品 (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 的新 monetization.onetimeproducts
服務,或 Play Developer Console UI。如要使用這項服務,可以直接呼叫 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(); // … } } } } });
折扣優惠層級的數量有限
你可以在折扣優惠層級指定數量上限,也就是只在優惠層級套用。範例如下:
- 超級螢幕保護程式提供 2 種螢幕保護程式產品:購買螢幕保護程式和折扣螢幕保護程式。
- 購買選項螢幕保護程式未設定數量限制。
- 折扣螢幕保護程式的優惠層級允許數量上限設為 3。
- 螢幕保護程式產品沒有產品層級的數量上限,因此使用者可以無限量購買這項產品。
- 使用者擁有 1 個折扣螢幕保護程式,並打算使用折扣螢幕保護程式再購買 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(); // … } } } });
沿用優惠標記
你可以為產品、購買選項或折扣優惠設定優惠標記。 折扣優惠會沿用購買選項優惠的優惠標記。 同樣地,如果是在產品層級指定買家標記,購買選項和折扣優惠都會沿用產品買家標記。
舉例來說,超級螢幕保護程式有兩項螢幕保護程式產品優惠:購買螢幕保護程式和折扣螢幕保護程式。
- 超級螢幕保護程式會顯示產品優惠標記
SSProductTag
。 - 購買選項螢幕保護程式含有優惠標記
SSPurchaseOptionTag
。 - 折扣螢幕保護程式含有優惠標記
SSDiscountOfferTag
。
在這個範例中,購買選項方案的 oneTimePurchaseOfferDetails.getOfferTagsList()
方法會傳回 SSProductTag
和 SSPurchaseOptionTag
。如果是折扣優惠,這個方法會傳回 SSProductTag
、SSPurchaseOptionTag
和 SSDiscountOfferTag
。