重要提示:如果您的應(yīng)用當(dāng)前使用AIDL來集成Google Play結(jié)算系統(tǒng),請(qǐng)參閱從AIDL遷移到Google Play結(jié)算庫的遷移指南,大致了解從AIDL遷移到Google Play結(jié)算庫時(shí)需要執(zhí)行的步驟。
本主題介紹了如何將Google Play結(jié)算庫集成到您的應(yīng)用中以開始銷售商品。在閱讀本主題之前,請(qǐng)確保您已按照做好準(zhǔn)備中的步驟提前設(shè)置了Google Play配置。
本主題包含一些代碼示例,它們基于GitHub上的官方示例應(yīng)用。如需查看您在集成時(shí)可使用的示例應(yīng)用和其他資源的完整列表,請(qǐng)參閱其他資源。
購買交易的生命周期
下面是一次性購買或訂閱的典型購買流程。
向用戶展示他們可以購買什么。
啟動(dòng)購買流程,以便用戶接受購買交易。
在您的服務(wù)器上驗(yàn)證購買交易。
向用戶提供內(nèi)容,并確認(rèn)內(nèi)容已傳送給用戶。還可以選擇性地將商品標(biāo)記為已消費(fèi),以便用戶可以再次購買商品。
訂閱會(huì)自動(dòng)續(xù)訂,直到被取消。訂閱可處于下面這幾種狀態(tài):
活躍:用戶信譽(yù)良好,可享用訂閱內(nèi)容。
已取消:用戶已取消訂閱,但在到期前仍可享用訂閱內(nèi)容。
處于寬限期:用戶遇到了付款問題,但仍可享用訂閱內(nèi)容,同時(shí)Google會(huì)重新嘗試通過相應(yīng)的付款方式扣款。
暫時(shí)保留:用戶遇到了付款問題,不能再享用訂閱內(nèi)容,同時(shí)Google會(huì)重新嘗試通過相應(yīng)的付款方式扣款。
已暫停:用戶暫停了其訂閱,在恢復(fù)之前不能享用訂閱內(nèi)容。
已到期:用戶已取消且不能再享用訂閱內(nèi)容。用戶在訂閱到期時(shí)會(huì)被視為流失。
購買令牌和訂單ID
Google Play使用購買令牌和訂單ID跟蹤商品和交易。
購買令牌是一個(gè)字符串,表示買家對(duì)Google Play上的商品的權(quán)利。它表明Google用戶有權(quán)使用由SKU表示的特定商品。您可以將購買令牌與Google Play Developer API一起使用。
訂單ID是一個(gè)字符串,表示Google Play上的財(cái)務(wù)交易。此字符串會(huì)包含在通過電子郵件發(fā)送給買家的收據(jù)中。您可以在銷售和付款報(bào)告中使用訂單ID來管理退款。
每當(dāng)發(fā)生財(cái)務(wù)交易時(shí),系統(tǒng)都會(huì)創(chuàng)建訂單ID。只有當(dāng)用戶完成購買流程時(shí),系統(tǒng)才會(huì)生成購買令牌。
對(duì)于一次性商品,每次購買交易都會(huì)創(chuàng)建一個(gè)新的購買令牌。大多數(shù)購買交易還會(huì)生成一個(gè)新的訂單ID。這條規(guī)則有一種例外情況,那就是不向用戶收取任何費(fèi)用時(shí),如促銷代碼中所述。
對(duì)于訂閱,首次購買交易會(huì)創(chuàng)建一個(gè)購買令牌和一個(gè)訂單ID。對(duì)于每個(gè)連續(xù)的結(jié)算周期,購買令牌將保持不變,但系統(tǒng)會(huì)發(fā)放一個(gè)新的訂單ID。升級(jí)、降級(jí)、替換和重新注冊(cè)都會(huì)創(chuàng)建新的購買令牌和訂單ID。
關(guān)于訂閱,請(qǐng)注意以下幾點(diǎn):
訂閱升級(jí)、降級(jí)和其他訂閱購買流程會(huì)生成購買令牌,這些令牌必須替換之前的購買令牌。您必須使出現(xiàn)在Google Play Developer API的linkedPurchaseToken字段中的購買令牌無效。如需了解詳情,請(qǐng)參閱正確實(shí)現(xiàn)linkedPurchaseToken以防止重復(fù)訂閱。
訂閱續(xù)訂的訂單號(hào)包含一個(gè)額外的整數(shù),它表示具體是第幾次續(xù)訂。例如,初始訂閱的訂單ID可能是GPA.1234-5678-9012-34567,后續(xù)訂單ID是GPA.1234-5678-9012-34567..0(第一次續(xù)訂)、GPA.1234-5678-9012-34567..1(第二次續(xù)訂),依此類推。
注意:如果用戶在購買應(yīng)用內(nèi)商品時(shí)沒有應(yīng)付款項(xiàng)(如在訂閱的免費(fèi)試訂期內(nèi)),則會(huì)生成金額為0美元的訂單ID。例如,當(dāng)用戶取消訂閱時(shí),訂閱將保持有效狀態(tài),直到結(jié)算周期結(jié)束。如果用戶決定重新注冊(cè),則其帳號(hào)中會(huì)有一些余額。在這種情況下,系統(tǒng)會(huì)創(chuàng)建一個(gè)新的購買令牌,創(chuàng)建一個(gè)金額為0美元的訂單ID,并在余額扣完后續(xù)訂。
錯(cuò)誤處理
Google Play結(jié)算庫會(huì)以BillingResult的形式返回錯(cuò)誤。BillingResult包含一個(gè)BillingResponseCode,它用于對(duì)您的應(yīng)用可能會(huì)遇到的與結(jié)算相關(guān)的錯(cuò)誤進(jìn)行分類。例如,如果您收到SERVICE_DISCONNECTED錯(cuò)誤代碼,則您的應(yīng)用應(yīng)重新初始化與Google Play的連接。此外,BillingResult還包含一條調(diào)試消息,它對(duì)于在開發(fā)過程中診斷錯(cuò)誤很有用。
連接到Google Play
與Google Play結(jié)算系統(tǒng)集成的第一步是將該庫添加到您的應(yīng)用中并初始化連接。
添加Google Play結(jié)算庫依賴項(xiàng)
注意:如果您已經(jīng)按照做好準(zhǔn)備指南中的說明操作,那么就已經(jīng)添加了必要的依賴項(xiàng),現(xiàn)在可以轉(zhuǎn)到下一部分。
將Google Play結(jié)算庫依賴項(xiàng)添加到應(yīng)用的build.gradle文件中,如下所示:
dependencies{
def billing_version="3.0.0"
implementation"com.android.billingclient:billing:$billing_version"
}
如果您使用的是Kotlin,Play結(jié)算庫KTX模塊包含了Kotlin擴(kuò)展程序和協(xié)程支持,可讓您在使用Google Play結(jié)算庫時(shí)編寫慣用的Kotlin代碼。如需將這些擴(kuò)展程序包含在項(xiàng)目中,請(qǐng)將以下依賴項(xiàng)添加到應(yīng)用的build.gradle文件中,如下所示:
dependencies{
def billing_version="3.0.0"
implementation"com.android.billingclient:billing-ktx:$billing_version"
}
初始化BillingClient
添加對(duì)Google Play結(jié)算庫的依賴關(guān)系后,您需要初始化BillingClient實(shí)例。BillingClient是Google Play結(jié)算庫與應(yīng)用的其余部分之間進(jìn)行通信的主接口。BillingClient為許多常見的結(jié)算操作提供了方便的方法,既有同步方法,又有異步方法。
如需創(chuàng)建BillingClient,請(qǐng)使用newBuilder()。為了接收有關(guān)購買交易的更新,您還必須調(diào)用setListener(),并傳遞對(duì)PurchasesUpdatedListener的引用。此監(jiān)聽器可接收應(yīng)用中所有購買交易的更新。
KOTLIN
private val purchasesUpdateListener=
PurchasesUpdatedListener{billingResult,purchases->
//To be implemented in a later section.
}
private var billingClient=BillingClient.newBuilder(activity)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build()
JAVA
private PurchasesUpdatedListener purchasesUpdatedListener=new PurchasesUpdatedListener(){
Override
public void onPurchasesUpdated(BillingResult billingResult,List<Purchase>purchases){
//To be implemented in a later section.
}
};
private BillingClient billingClient=BillingClient.newBuilder(activity)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build();
與Google Play建立連接
創(chuàng)建BillingClient后,您需要與Google Play建立連接。
如需連接到Google Play,請(qǐng)調(diào)用startConnection()。連接過程是異步進(jìn)行的,因此您必須實(shí)現(xiàn)BillingClientStateListener,以便在客戶端的設(shè)置完成后且它準(zhǔn)備好發(fā)出進(jìn)一步的請(qǐng)求時(shí)接收回調(diào)。
此外,您還必須實(shí)現(xiàn)重試邏輯,以處理與Google Play失去連接的問題。如需實(shí)現(xiàn)重試邏輯,請(qǐng)?zhí)鎿QonBillingServiceDisconnected()回調(diào)方法,并確保BillingClient先調(diào)用startConnection()方法以重新連接到Google Play,然后再發(fā)出進(jìn)一步的請(qǐng)求。
以下示例演示了如何啟動(dòng)連接并測(cè)試它是否已準(zhǔn)備就緒可供使用:
KOTLIN
billingClient.startConnection(object:BillingClientStateListener{
override fun onBillingSetupFinished(billingResult:BillingResult){
if(billingResult.responseCode==BillingResponseCode.OK){
//The BillingClient is ready.You can query purchases here.
}
}
override fun onBillingServiceDisconnected(){
//Try to restart the connection on the next request to
//Google Play by calling the startConnection()method.
}
})
JAVA
billingClient.startConnection(new BillingClientStateListener(){
Override
public void onBillingSetupFinished(BillingResult billingResult){
if(billingResult.getResponseCode()==BillingResponseCode.OK){
//The BillingClient is ready.You can query purchases here.
}
}
Override
public void onBillingServiceDisconnected(){
//Try to restart the connection on the next request to
//Google Play by calling the startConnection()method.
}
});
注意:強(qiáng)烈建議您實(shí)現(xiàn)自己的連接重試邏輯并替換onBillingServiceDisconnected()方法。請(qǐng)確保在執(zhí)行任何方法時(shí)都與BillingClient保持連接。
展示可供購買的商品
與Google Play建立連接后,您就可以查詢可售的商品并將其展示給用戶了。如需向Google Play查詢應(yīng)用內(nèi)商品詳情,請(qǐng)調(diào)用querySkuDetailsAsync()。在將商品展示給用戶之前,查詢SKU詳情是非常重要的一步,因?yàn)椴樵儠?huì)返回本地化的商品信息。對(duì)于訂閱,請(qǐng)確保您的商品展示符合所有Play政策。
調(diào)用querySkuDetailsAsync()時(shí),應(yīng)傳遞SkuDetailsParams的實(shí)例,用于指定在Google Play管理中心創(chuàng)建的商品ID字符串的列表以及SkuType。SkuType可以是SkuType.INAPP(針對(duì)一次性商品),也可以是SkuType.SUBS(針對(duì)訂閱)。
為了處理該異步操作的結(jié)果,您還必須指定實(shí)現(xiàn)SkuDetailsResponseListener接口的監(jiān)聽器。然后,您可以替換onSkuDetailsResponse(),該方法會(huì)在查詢完成時(shí)通知監(jiān)聽器,如以下示例所示:
KOTLIN
fun querySkuDetails(){
val skuList=ArrayList<String>()
skuList.add("premium_upgrade")
skuList.add("gas")
val params=SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(SkuType.INAPP)
withContext(Dispatchers.IO){
billingClient.querySkuDetailsAsync(params.build()){billingResult,skuDetailsList->
//Process the result.
}
}
}
JAVA
List<String>skuList=new ArrayList<>();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params=SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener(){
Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails>skuDetailsList){
//Process the result.
}
});
Google Play結(jié)算庫會(huì)將查詢結(jié)果存儲(chǔ)在SkuDetails對(duì)象的List中。您隨后可以對(duì)該列表中的每個(gè)SkuDetails對(duì)象調(diào)用各種方法,以查看應(yīng)用內(nèi)商品的相關(guān)信息,如其價(jià)格或說明。如需查看可用的商品詳情,請(qǐng)參閱SkuDetails類中的方法列表。
在提供待售商品之前,檢查用戶是否尚未擁有該商品。如果用戶的消耗型商品仍在他們的商品庫中,他們必須先消耗掉該商品,然后才能再次購買。
在提供訂閱之前,驗(yàn)證用戶是否尚未訂閱。
注意:有些Android設(shè)備安裝的可能是舊版Google Play商店應(yīng)用,不支持訂閱等某些商品類型。在您的應(yīng)用進(jìn)入結(jié)算流程之前,您可以調(diào)用isFeatureSupported()以確定設(shè)備是否支持您要銷售的商品。如需查看可支持的商品類型的列表,請(qǐng)參閱BillingClient.FeatureType。
啟動(dòng)購買流程
如需從應(yīng)用發(fā)起購買請(qǐng)求,請(qǐng)從應(yīng)用的主線程調(diào)用launchBillingFlow()方法。此方法接受對(duì)BillingFlowParams對(duì)象的引用,該對(duì)象包含通過調(diào)用querySkuDetailsAsync()獲取的相關(guān)SkuDetails對(duì)象。如需創(chuàng)建BillingFlowParams對(duì)象,請(qǐng)使用BillingFlowParams.Builder類。
KOTLIN
//An activity reference from which the billing flow will be launched.
val activity:Activity=...;
//Retrieve a value for"skuDetails"by calling querySkuDetailsAsync().
val flowParams=BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build()
val responseCode=billingClient.launchBillingFlow(activity,flowParams).responseCode
JAVA
//An activity reference from which the billing flow will be launched.
Activity activity=...;
//Retrieve a value for"skuDetails"by calling querySkuDetailsAsync().
BillingFlowParams billingFlowParams=BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
int responseCode=billingClient.launchBillingFlow(activity,billingFlowParams).getResponseCode();
//Handle the result.
launchBillingFlow()方法會(huì)返回BillingClient.BillingResponseCode中列出的幾個(gè)響應(yīng)代碼之一。請(qǐng)務(wù)必檢查此結(jié)果,以確保在啟動(dòng)購買流程時(shí)沒有錯(cuò)誤。BillingResponseCode為OK表示成功啟動(dòng)。
成功調(diào)用launchBillingFlow()后,系統(tǒng)會(huì)顯示Google Play購買屏幕。圖1顯示了訂閱的購買屏幕:
圖1.Google Play購買屏幕顯示了可供購買的訂閱。
Google Play會(huì)調(diào)用onPurchasesUpdated(),以將購買操作的結(jié)果傳送給實(shí)現(xiàn)PurchasesUpdatedListener接口的監(jiān)聽器。您可以在初始化客戶端時(shí)使用setListener()方法指定監(jiān)聽器。
您必須實(shí)現(xiàn)onPurchasesUpdated()來處理可能的響應(yīng)代碼。以下示例展示了如何替換onPurchasesUpdated():
KOTLIN
override fun onPurchasesUpdated(billingResult:BillingResult,purchases:List<Purchase>?){
if(billingResult.responseCode==BillingResponseCode.OK&&purchases!=null){
for(purchase in purchases){
handlePurchase(purchase)
}
}else if(billingResult.responseCode==BillingResponseCode.USER_CANCELED){
//Handle an error caused by a user cancelling the purchase flow.
}else{
//Handle any other error codes.
}
}
JAVA
Override
void onPurchasesUpdated(BillingResult billingResult,List<Purchase>purchases){
if(billingResult.getResponseCode()==BillingResponseCode.OK
&&purchases!=null){
for(Purchase purchase:purchases){
handlePurchase(purchase);
}
}else if(billingResult.getResponseCode()==BillingResponseCode.USER_CANCELED){
//Handle an error caused by a user cancelling the purchase flow.
}else{
//Handle any other error codes.
}
}
如果成功購買商品,系統(tǒng)會(huì)顯示Google Play購買成功屏幕,類似于圖2。
圖2.Google Play的購買成功屏幕。
如果成功購買商品,系統(tǒng)還會(huì)生成購買令牌,它是一個(gè)唯一標(biāo)識(shí)符,表示用戶及其所購應(yīng)用內(nèi)商品的商品ID。您的應(yīng)用可以在本地存儲(chǔ)購買令牌,不過我們建議您將令牌傳遞到安全的后端服務(wù)器,您隨后可以在該服務(wù)器上驗(yàn)證購買交易及防范欺詐行為。下一部分對(duì)此過程進(jìn)行了詳細(xì)說明。
用戶還會(huì)收到包含交易收據(jù)的電子郵件,其中包含訂單ID或交易的唯一ID。用戶每次購買一次性商品時(shí),都會(huì)收到包含唯一訂單ID的電子郵件。此外,用戶最初購買訂閱時(shí)以及后續(xù)定期自動(dòng)續(xù)訂時(shí),也會(huì)收到這樣的電子郵件。您可以在Google Play管理中心內(nèi)使用訂單ID來管理退款。
處理購買交易
用戶完成購買交易后,您的應(yīng)用需要處理該購買交易。在大多數(shù)情況下,您的應(yīng)用會(huì)通過PurchasesUpdatedListener收到購買交易的通知。但在某些情況下,您的應(yīng)用通過調(diào)用BillingClient.queryPurchases()得知購買交易,如提取購買交易中所述。
您的應(yīng)用應(yīng)按以下方式處理購買交易:
驗(yàn)證購買交易。
向用戶提供內(nèi)容,并確認(rèn)內(nèi)容已傳送給用戶。還可以選擇性地將商品標(biāo)記為已消費(fèi),以便用戶可以再次購買商品。
如需驗(yàn)證購買交易,請(qǐng)先檢查購買交易的狀態(tài)是否為PURCHASED。如果購買交易的狀態(tài)為PENDING,則您應(yīng)按照處理待處理的交易中的說明處理購買交易。對(duì)于通過onPurchaseUpdated()或queryPurchases接收的購買交易,您應(yīng)在應(yīng)用授予權(quán)利之前進(jìn)一步驗(yàn)證購買交易以確保其合法性。如需了解如何正確驗(yàn)證購買交易,請(qǐng)參閱在授予權(quán)利前驗(yàn)證購買交易。
一旦您驗(yàn)證了購買交易,您的應(yīng)用就可以向用戶授予權(quán)利了。授予權(quán)利后,您的應(yīng)用必須確認(rèn)購買交易。此確認(rèn)會(huì)告知Google Play您已授予購買權(quán)。
注意:如果您在三天內(nèi)未確認(rèn)購買交易,用戶會(huì)自動(dòng)收到退款,并且Google Play會(huì)撤消該購買交易。
注意:使用2.0之前的Google Play結(jié)算庫版本時(shí),不需要確認(rèn)。
授予權(quán)利并確認(rèn)購買交易的流程取決于購買的是非消耗型商品、消耗型商品,還是訂閱。
對(duì)于消耗型商品,consumeAsync()方法滿足確認(rèn)要求,并且表明您的應(yīng)用已授予用戶權(quán)利。此外,通過此方法,您的應(yīng)用可讓一次性商品可供再次購買。
如需表明某件一次性商品已被消耗,請(qǐng)調(diào)用consumeAsync()并添加Google Play應(yīng)在用戶重新購買時(shí)提供的購買令牌。您還必須傳遞一個(gè)實(shí)現(xiàn)ConsumeResponseListener接口的對(duì)象。該對(duì)象用于處理消耗操作的結(jié)果。您可以替換onConsumeResponse()方法,Google Play結(jié)算庫會(huì)在消耗操作完成時(shí)調(diào)用該方法。
以下示例展示了如何使用關(guān)聯(lián)的購買令牌來消耗商品:
KOTLIN
fun handlePurchase(purchase:Purchase){
//Purchase retrieved from BillingClient#queryPurchases or your PurchasesUpdatedListener.
val purchase:Purchase=...;
//Verify the purchase.
//Ensure entitlement was not already granted for this purchaseToken.
//Grant entitlement to the user.
val consumeParams=
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build()
billingClient.consumeAsync(consumeParams,{billingResult,outToken->
if(billingResult.responseCode==BillingResponseCode.OK){
//Handle the success of the consume operation.
}
})
}
JAVA
void handlePurchase(Purchase purchase){
//Purchase retrieved from BillingClient#queryPurchases or your PurchasesUpdatedListener.
Purchase purchase=...;
//Verify the purchase.
//Ensure entitlement was not already granted for this purchaseToken.
//Grant entitlement to the user.
ConsumeParams consumeParams=
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
ConsumeResponseListener listener=new ConsumeResponseListener(){
Override
public void onConsumeResponse(BillingResult billingResult,String purchaseToken){
if(billingResult.getResponseCode()==BillingResponseCode.OK){
//Handle the success of the consume operation.
}
}
};
billingClient.consumeAsync(consumeParams,listener);
}
注意:由于消耗請(qǐng)求偶爾會(huì)失敗,因此您必須檢查安全的后端服務(wù)器,確保所有購買令牌都未被使用過,這樣您的應(yīng)用就不會(huì)針對(duì)同一購買交易多次授予權(quán)利。或者,您的應(yīng)用也可以等到您收到Google Play發(fā)來的成功消耗響應(yīng)后再授予權(quán)利。如果您選擇在Google Play發(fā)來成功消耗響應(yīng)之前不讓用戶消耗所購商品,那么您必須非常小心,在消耗請(qǐng)求發(fā)出后時(shí)刻跟蹤相應(yīng)商品。
如需確認(rèn)非消耗型商品的購買交易,請(qǐng)使用結(jié)算庫中的BillingClient.acknowledgePurchase()或Google Play Developer API中的Product.Purchases.Acknowledge。在確認(rèn)購買交易之前,您的應(yīng)用應(yīng)使用Google Play結(jié)算庫中的isAcknowledged()方法或Google Play Developer API中的acknowledgementState字段檢查該購買交易是否已經(jīng)過確認(rèn)。
以下示例展示了如何使用Google Play結(jié)算庫來確認(rèn)購買交易:
KOTLIN
val client:BillingClient=...
val acknowledgePurchaseResponseListener:AcknowledgePurchaseResponseListener=...
fun handlePurchase(){
if(purchase.purchaseState===PurchaseState.PURCHASED){
if(!purchase.isAcknowledged){
val acknowledgePurchaseParams=AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
val ackPurchaseResult=withContext(Dispatchers.IO){
client.acknowledgePurchase(acknowledgePurchaseParams.build())
}
}
}
}
JAVA
BillingClient client=...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener=...
void handlePurchase(Purchase purchase){
if(purchase.getPurchaseState()==PurchaseState.PURCHASED){
if(!purchase.isAcknowledged()){
AcknowledgePurchaseParams acknowledgePurchaseParams=
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
client.acknowledgePurchase(acknowledgePurchaseParams,acknowledgePurchaseResponseListener);
}
}
}
訂閱的處理方式與非消耗型商品類似。您可以使用Google Play結(jié)算庫中的BillingClient.acknowledgePurchase()或Google Play Developer API中的Purchases.Subscriptions.Acknowledge確認(rèn)訂閱。所有初始訂閱購買交易都需要確認(rèn)。訂閱續(xù)訂不需要確認(rèn)。如需詳細(xì)了解訂閱何時(shí)需要確認(rèn),請(qǐng)參閱銷售訂閱內(nèi)容主題。
提取購買交易
使用PurchasesUpdatedListener監(jiān)聽購買交易更新不足以確保您的應(yīng)用會(huì)處理所有購買交易。有時(shí)您的應(yīng)用可能不知道用戶進(jìn)行的部分購買交易。在下面這幾種情況下,您的應(yīng)用可能會(huì)跟蹤不到或不知道購買交易:
在購買過程中出現(xiàn)網(wǎng)絡(luò)問題:用戶成功購買了商品并收到了Google的確認(rèn)消息,但他們的設(shè)備在通過PurchasesUpdatedListener收到購買交易的通知之前失去了網(wǎng)絡(luò)連接。
多臺(tái)設(shè)備:用戶在一臺(tái)設(shè)備上購買了一件商品,然后在切換設(shè)備時(shí)期望看到該商品。
處理在您的應(yīng)用外進(jìn)行的購買交易:某些購買交易(如促銷活動(dòng)兌換)可能會(huì)在您的應(yīng)用外進(jìn)行。
為了處理這些情況,請(qǐng)確保您的應(yīng)用在onResume()和onCreate()方法中調(diào)用BillingClient.queryPurchases(),以確保所有購買交易都得到成功處理,如處理購買交易中所述。
處理在您的應(yīng)用外進(jìn)行的購買交易
某些購買交易(如促銷活動(dòng)兌換)可能發(fā)生在您的應(yīng)用外。當(dāng)用戶在您的應(yīng)用外進(jìn)行購買交易時(shí),他們希望您的應(yīng)用顯示應(yīng)用內(nèi)消息,或使用某種通知機(jī)制告知用戶應(yīng)用已正確接收并處理該購買交易。下面是一些可接受的機(jī)制:
顯示應(yīng)用內(nèi)彈出式消息。
將消息傳送到應(yīng)用內(nèi)消息箱,并清楚地指出應(yīng)用內(nèi)消息箱中有新消息。
使用操作系統(tǒng)通知消息。
請(qǐng)注意,當(dāng)您的應(yīng)用識(shí)別出購買交易時(shí),它有可能處于任何狀態(tài)。甚至有可能在用戶進(jìn)行購買交易時(shí)根本沒有安裝您的應(yīng)用。無論應(yīng)用處于什么狀態(tài),用戶都希望在繼續(xù)使用應(yīng)用時(shí)收到其所購商品。
無論用戶進(jìn)行購買交易時(shí)應(yīng)用處于什么狀態(tài),您都必須檢測(cè)購買交易。不過,在一些例外情況下,不立即通知用戶已收到商品或許是可以接受的。例如:
當(dāng)用戶在玩游戲時(shí),顯示消息可能會(huì)讓用戶分心。在這種情況下,必須待游戲結(jié)束后再通知用戶。
在出現(xiàn)過場(chǎng)動(dòng)畫時(shí),顯示消息可能會(huì)讓用戶分心。在這種情況下,必須待過場(chǎng)動(dòng)畫結(jié)束后再通知用戶。
當(dāng)用戶在游戲中學(xué)習(xí)初始教程和進(jìn)行用戶設(shè)置時(shí)。我們建議您在新用戶打開游戲后立即將獎(jiǎng)勵(lì)通知用戶,或在用戶進(jìn)行初始設(shè)置期間通知他們。不過,您也可以等到用戶正式進(jìn)入游戲環(huán)節(jié)時(shí)再通知用戶。
在斟酌何時(shí)以及如何通知用戶在您的應(yīng)用外進(jìn)行的購買交易時(shí),一定要把用戶放在心上。如果用戶沒有立即收到通知,他們可能會(huì)感到困惑,并且可能會(huì)停止使用您的應(yīng)用,與用戶支持團(tuán)隊(duì)聯(lián)系,或在社交媒體上抱怨。
處理待處理的交易
注意:只有Google Play結(jié)算庫2.0及更高版本支持待處理的交易。
注意:其他付款方式不可用于訂閱購買交易。
Google Play支持待處理的交易,即從用戶發(fā)起購買交易到購買交易的付款方式得到處理期間需要執(zhí)行一個(gè)或多個(gè)額外步驟的交易。在Google通知您已通過用戶的付款方式成功扣款之前,您的應(yīng)用不得授予對(duì)這些類型的購買交易的權(quán)利。
例如,用戶可以選擇現(xiàn)金作為付款方式來創(chuàng)建應(yīng)用內(nèi)商品的PENDING購買交易。然后,用戶可以選擇在一家實(shí)體店完成交易,并通過通知和電子郵件收到一個(gè)代碼。當(dāng)用戶到達(dá)實(shí)體店時(shí),他們可以在收銀員處兌換該代碼并用現(xiàn)金支付。Google隨后會(huì)通知您和用戶已收到現(xiàn)金。您的應(yīng)用隨后就可以授予用戶權(quán)利了。
如要啟用“待處理的購買交易”功能,請(qǐng)?jiān)诔跏蓟瘧?yīng)用期間調(diào)用enablePendingPurchases()。
當(dāng)您的應(yīng)用通過PurchasesUpdatedListener或由于調(diào)用queryPurchases()而收到新的購買交易時(shí),使用getPurchaseState()方法確定購買交易的狀態(tài)是PURCHASED還是PENDING。請(qǐng)注意,只有在狀態(tài)為PURCHASED時(shí),您才能授予權(quán)利。如果您的應(yīng)用在用戶完成購買交易時(shí)正在運(yùn)行,系統(tǒng)會(huì)再次調(diào)用PurchasesUpdatedListener,并且PurchaseState現(xiàn)在為PURCHASED。此時(shí),您的應(yīng)用可以使用處理一次性購買的標(biāo)準(zhǔn)方法處理購買交易。此外,您的應(yīng)用還應(yīng)在其onResume()和onCreate()方法中調(diào)用queryPurchases(),以處理您的應(yīng)用未在運(yùn)行時(shí)過渡到PURCHASED狀態(tài)的購買交易。
注意:只有在狀態(tài)為PURCHASED時(shí),您才能確認(rèn)購買交易。當(dāng)購買交易處于PENDING狀態(tài)時(shí),您不能確認(rèn)。
您的應(yīng)用還可以通過監(jiān)聽OneTimeProductNotifications,將實(shí)時(shí)開發(fā)者通知與待處理的購買交易一起使用。當(dāng)購買交易從PENDING過渡到PURCHASED時(shí),您的應(yīng)用會(huì)收到ONE_TIME_PRODUCT_PURCHASED通知。如果購買交易被取消,您的應(yīng)用會(huì)收到ONE_TIME_PRODUCT_CANCELED通知。如果客戶沒有在規(guī)定的時(shí)間范圍內(nèi)完成付款,就會(huì)發(fā)生這種情況。當(dāng)收到這些通知時(shí),您可以使用Google Play Developer API,該API包含Purchases.products的PENDING狀態(tài)。
注意:待處理的交易可由許可測(cè)試人員進(jìn)行測(cè)試。除了兩張測(cè)試信用卡之外,許可測(cè)試人員還可以使用兩種測(cè)試付款方式,以測(cè)試在幾分鐘后自動(dòng)完成或取消的延遲付款方式。在測(cè)試您的應(yīng)用時(shí),您應(yīng)驗(yàn)證您的應(yīng)用是否不會(huì)在用戶使用這兩種付款方式中的任意一種購買后立即授予權(quán)利或確認(rèn)購買交易。使用自動(dòng)完成的測(cè)試付款方式購買時(shí),您應(yīng)驗(yàn)證您的應(yīng)用是否會(huì)在購買完成后授予權(quán)利并確認(rèn)購買交易。