Android Goolge 支付 In app集成(一)

本篇文章是官網(wǎng)中文版。有外網(wǎng)的小伙伴可以直接訪問官網(wǎng)地址和代碼示例

https://developer.android.com/google/play/billing/billing_integrate?hl=zh-cn
https://github.com/googlesamples/android-play-billing

In-app Billing API

您的應(yīng)用會(huì)通過相應(yīng) API (由設(shè)備上安裝的 Google Play 應(yīng)用提供)來訪問應(yīng)用內(nèi)購(gòu)買結(jié)算服務(wù)。 然后,Google Play 應(yīng)用會(huì)在您的應(yīng)用和 Google Play 服務(wù)器之間傳送購(gòu)買結(jié)算請(qǐng)求和響應(yīng)。 實(shí)際上,您的應(yīng)用從不直接與 Google Play 服務(wù)器通信。 而是通過進(jìn)程間通信 (IPC) 向 Google Play 應(yīng)用發(fā)送購(gòu)買結(jié)算請(qǐng)求并接收 Google Play 應(yīng)用發(fā)來的響應(yīng)。此外,您的應(yīng)用也不管理其與 Google Play 服務(wù)器之間的任何網(wǎng)絡(luò)連接。

應(yīng)用內(nèi)購(gòu)買結(jié)算只能在您通過 Google Play 發(fā)布的應(yīng)用中實(shí)現(xiàn)。 要完成應(yīng)用內(nèi)購(gòu)買請(qǐng)求,Google Play 應(yīng)用必須能夠通過網(wǎng)絡(luò)訪問 Google Play 服務(wù)器。

應(yīng)用內(nèi)購(gòu)買結(jié)算版本 3 是最新版本,依然具有非常廣泛的兼容性,可用于各種 Android 設(shè)備。 運(yùn)行 Android 2.2(API 級(jí)別 8)或更高版本且安裝了最新版本的 Google Play 應(yīng)用的設(shè)備(絕大多數(shù)有效設(shè)備)都支持使用應(yīng)用內(nèi)購(gòu)買結(jié)算版本 3。

版本 3 的功能

應(yīng)用內(nèi)購(gòu)買結(jié)算版本 3 提供以下功能:

  • 您的應(yīng)用通過簡(jiǎn)化的 API 發(fā)送請(qǐng)求,讓用戶可以輕松地向 Google Play 請(qǐng)求商品詳情并訂購(gòu)應(yīng)用內(nèi)商品。 API 可以根據(jù)用戶對(duì)商品的所有權(quán)快速恢復(fù)商品。
  • API 會(huì)在購(gòu)買完成時(shí)將訂單信息同步傳送至設(shè)備。
  • 所有購(gòu)買都是托管的(也就是說,Google Play 負(fù)責(zé)跟蹤用戶對(duì)應(yīng)用內(nèi)商品的所有權(quán))。 用戶無(wú)論何時(shí)都只能擁有同一應(yīng)用內(nèi)商品的一個(gè)副本而不能擁有多個(gè)副本。
  • 您可以消耗所購(gòu)商品。消耗后,此商品將切換回未被擁有狀態(tài),且可被用戶從 Google Play 中再次購(gòu)買。
  • API 支持訂閱

如需了解有關(guān)其他版本的應(yīng)用內(nèi)購(gòu)買結(jié)算的詳情,請(qǐng)參閱版本說明

應(yīng)用內(nèi)商品

應(yīng)用內(nèi)商品是您在應(yīng)用內(nèi)向用戶出售的數(shù)字商品。 包括游戲內(nèi)貨幣、旨在改善用戶體驗(yàn)的應(yīng)用功能升級(jí)以及應(yīng)用中的新增內(nèi)容。

應(yīng)用內(nèi)購(gòu)買結(jié)算只能用于銷售數(shù)字內(nèi)容,而不能用于銷售實(shí)體商品、個(gè)人服務(wù)或任何需要進(jìn)行實(shí)物交付的商品/服務(wù)。 與明碼標(biāo)價(jià)的應(yīng)用不同,在用戶購(gòu)買應(yīng)用內(nèi)商品后,系統(tǒng)不會(huì)提供退款窗口。

Google Play 不提供任何形式的內(nèi)容交付。您需要自行負(fù)責(zé)在應(yīng)用中出售的數(shù)字內(nèi)容的交付。 應(yīng)用內(nèi)商品始終僅與一個(gè)應(yīng)用明確關(guān)聯(lián)。 也就是說,在一個(gè)應(yīng)用中不能購(gòu)買為另一個(gè)應(yīng)用發(fā)布的應(yīng)用內(nèi)商品,即使這兩個(gè)應(yīng)用來自相同的開發(fā)者也是如此。

商品類型

應(yīng)用內(nèi)購(gòu)買結(jié)算支持多種商品類型,因此您可靈活選擇如何通過您的應(yīng)用獲利。 無(wú)論是哪種商品,您均能通過 Google Play Developer Console 進(jìn)行定義。

您可以為應(yīng)用內(nèi)購(gòu)買結(jié)算應(yīng)用指定以下兩類商品:托管的應(yīng)用內(nèi)商品訂閱。 Google Play 會(huì)針對(duì)每位用戶處理和跟蹤您應(yīng)用中的應(yīng)用內(nèi)商品和訂閱的所有權(quán)。詳細(xì)了解應(yīng)用內(nèi)購(gòu)買結(jié)算版本 3 支持的商品類型。

Google Play Developer Console

在 Developer Console 上,您不僅能發(fā)布應(yīng)用內(nèi)購(gòu)買結(jié)算應(yīng)用,還能管理在您應(yīng)用中可以購(gòu)買的各種應(yīng)用內(nèi)商品。

對(duì)于與您的應(yīng)用相關(guān)聯(lián)的數(shù)字商品(包括一次性商品和定期訂閱),您可以為其創(chuàng)建商品列表。 對(duì)于每件商品,您都可以定義下列信息:

  • 唯一商品 ID(也稱為 SKU)。
  • 商品類型。
  • 定價(jià)。
  • 說明。
  • Google Play 應(yīng)如何處理和跟蹤用戶對(duì)該商品的購(gòu)買。

如果您以相同價(jià)格出售多個(gè)應(yīng)用或應(yīng)用內(nèi)商品,可以添加定價(jià)模板,從集中的位置來管理這些價(jià)格。 使用定價(jià)模板時(shí),您可以在提供的價(jià)格中包含地方稅,或者您也可以提供價(jià)格并讓系統(tǒng)為這些價(jià)格添加地方稅。 您可以對(duì)定價(jià)模板中的價(jià)格進(jìn)行更改(例如更新一些國(guó)家/地區(qū)的匯率),您的更改會(huì)應(yīng)用到與此模板關(guān)聯(lián)的應(yīng)用和應(yīng)用內(nèi)商品。

您還可以創(chuàng)建測(cè)試帳戶,授權(quán)這些帳戶測(cè)試尚未發(fā)布的應(yīng)用。

要了解如何使用 Developer Console 配置您的應(yīng)用內(nèi)商品和商品列表,請(qǐng)參閱管理應(yīng)用內(nèi)購(gòu)買結(jié)算

Google Play 購(gòu)買流程

Google Play 使用的結(jié)賬后端服務(wù)與用于應(yīng)用購(gòu)買的服務(wù)相同,因此您的用戶將獲得一致且熟悉的購(gòu)買流程體驗(yàn)。

重要說明:您必須有 Google Payments 商家?guī)ぬ?hào)才能在 Google Play 上使用應(yīng)用內(nèi)購(gòu)買結(jié)算服務(wù)。

購(gòu)買開始時(shí),您的應(yīng)用需要針對(duì)相應(yīng)的應(yīng)用內(nèi)商品發(fā)送購(gòu)買結(jié)算請(qǐng)求。 然后,Google Play 會(huì)處理此次交易的所有結(jié)賬詳情,包括請(qǐng)求和驗(yàn)證付款方式以及處理財(cái)務(wù)交易。

結(jié)賬流程完成后,Google Play 會(huì)向您的應(yīng)用發(fā)送購(gòu)買詳情,例如訂單號(hào)、訂單日期和時(shí)間以及所付價(jià)格。 您的應(yīng)用從不需要處理任何財(cái)務(wù)交易,這些事宜完全由 Google Play 負(fù)責(zé)。

示例應(yīng)用

為了幫助您將應(yīng)用內(nèi)購(gòu)買結(jié)算集成到應(yīng)用中,Android SDK 提供了一個(gè)示例應(yīng)用,向您演示如何在應(yīng)用內(nèi)銷售應(yīng)用內(nèi)商品和訂閱。

適用于 Version 3 API 的 TrivialDrive 示例演示了如何使用 In-app Billing Version 3 API 在賽車游戲中實(shí)現(xiàn)應(yīng)用內(nèi)商品和訂閱購(gòu)買。 該應(yīng)用不僅演示了如何發(fā)送應(yīng)用內(nèi)購(gòu)買結(jié)算請(qǐng)求以及處理來自 Google Play 的同步響應(yīng), 還演示了如何通過此 API 記錄商品的消耗情況。 版本 3 示例包括多種工具類,非常便于處理應(yīng)用內(nèi)購(gòu)買結(jié)算操作和執(zhí)行自動(dòng)簽名驗(yàn)證。

建議:請(qǐng)務(wù)必在發(fā)布應(yīng)用前混淆其中的代碼。 如需了解詳細(xì)信息,請(qǐng)參閱安全性和設(shè)計(jì)

混淆您的代碼

您應(yīng)混淆應(yīng)用內(nèi)購(gòu)買結(jié)算代碼,讓攻擊者難以對(duì)您的安全協(xié)議和其他應(yīng)用組件進(jìn)行反向工程。 我們建議您至少對(duì)代碼運(yùn)行 Proguard 等代碼混淆工具。

除了運(yùn)行代碼混淆程序以外,我們還建議您使用以下技術(shù)混淆您的應(yīng)用內(nèi)購(gòu)買結(jié)算代碼。

  • 將方法內(nèi)嵌入其他方法中。
  • 創(chuàng)建動(dòng)態(tài)字符串,而不是將其定義為常量。
  • 使用 Java 反射來調(diào)用方法。

使用這些技術(shù)有助于縮小應(yīng)用的受攻擊范圍,并最大程度幫助您抵御會(huì)對(duì)應(yīng)用內(nèi)購(gòu)買結(jié)算實(shí)現(xiàn)造成損害的攻擊。

-keep class com.android.vending.billing.**

遷移注意事項(xiàng)

In-app Billing Version 2 API 已于 2015 年 1 月關(guān)閉。如果您現(xiàn)有的應(yīng)用內(nèi)購(gòu)買結(jié)算實(shí)現(xiàn)使用的是 API 版本 2 或更低版本,則必須遷移到應(yīng)用內(nèi)購(gòu)買結(jié)算版本 3

遷移后,托管和未托管的商品處理方式如下:

  • 您之前在 Developer Console 中定義的托管商品和訂閱仍能使用版本 3。
  • 對(duì)于您已經(jīng)為現(xiàn)有應(yīng)用定義的非托管商品,如果您使用 Version 3 API 針對(duì)這些商品發(fā)起購(gòu)買請(qǐng)求,這些商品將被視為托管商品。 您無(wú)需在 Developer Console 中為這些商品創(chuàng)建新的商品條目,且能使用相同的商品 ID 來管理這些商品。

實(shí)現(xiàn)應(yīng)用內(nèi)購(gòu)買結(jié)算

Google Play 上的應(yīng)用內(nèi)購(gòu)買結(jié)算提供了一個(gè)直接、簡(jiǎn)單的界面,讓您可以使用 Google Play 發(fā)送應(yīng)用內(nèi)購(gòu)買結(jié)算請(qǐng)求和管理應(yīng)用內(nèi)購(gòu)買結(jié)算交易。 下面的信息涵蓋了如何使用 API 版本 3 從您的應(yīng)用調(diào)用應(yīng)用內(nèi)購(gòu)買結(jié)算服務(wù)的基本知識(shí)。

:要查看完整實(shí)現(xiàn)并了解如何測(cè)試您的應(yīng)用,請(qǐng)參閱出售應(yīng)用內(nèi)商品培訓(xùn)課程。 培訓(xùn)課程提供了一個(gè)完整的示例應(yīng)用內(nèi)購(gòu)買結(jié)算應(yīng)用,包括多種工具類,便于處理關(guān)鍵任務(wù)(例如設(shè)置您的連接、發(fā)送購(gòu)買結(jié)算請(qǐng)求和處理來自 Google Play 的響應(yīng)以及管理后臺(tái)線程),這樣您就可以從主 Activity 調(diào)用應(yīng)用內(nèi)購(gòu)買結(jié)算。

開始前,請(qǐng)務(wù)必閱讀應(yīng)用內(nèi)購(gòu)買結(jié)算概覽,以便熟悉一些概念,使您能夠輕松實(shí)現(xiàn)應(yīng)用內(nèi)購(gòu)買結(jié)算。

要在您的應(yīng)用中實(shí)現(xiàn)應(yīng)用內(nèi)購(gòu)買結(jié)算,您需要執(zhí)行以下操作:

  1. 將應(yīng)用內(nèi)購(gòu)買結(jié)算庫(kù)添加到您的項(xiàng)目中。
  2. 更新您的 AndroidManifest.xml 文件。
  3. 創(chuàng)建 ServiceConnection 并將其綁定到 IInAppBillingService
  4. 從您的應(yīng)用發(fā)送應(yīng)用內(nèi)購(gòu)買結(jié)算請(qǐng)求至IInAppBillingService
  5. 處理來自 Google Play 的應(yīng)用內(nèi)購(gòu)買結(jié)算請(qǐng)求響應(yīng)。

將 AIDL 文件添加到您的項(xiàng)目中

IInAppBillingService.aidl 是一種定義應(yīng)用內(nèi)購(gòu)買結(jié)算版本 3 服務(wù)接口的 Android 接口定義語(yǔ)言 (AIDL) 文件。 您可以使用此接口通過調(diào)用 IPC 方法調(diào)用來發(fā)送結(jié)算請(qǐng)求。

要獲取 AIDL 文件,請(qǐng)執(zhí)行以下操作:

  1. 打開 Android SDK 管理器
  2. 在 SDK 管理器中,展開 Extras 部分。
  3. 選擇 Google Play Billing Library
  4. 點(diǎn)擊 Install packages 完成下載。

IInAppBillingService.aidl 文件將安裝到 <sdk>/extras/google/play_billing/

要將 AIDL 添加到您的項(xiàng)目,請(qǐng)執(zhí)行以下操作:

  1. 首先,下載 Google Play Billing Library 到您的 Android 項(xiàng)目:
    1. 選擇 Tools > Android > SDK Manager
    2. Appearance & Behavior > System Settings > Android SDK 下面,選擇 SDK Tools 標(biāo)簽以選擇并下載 Google Play Billing Library
  2. 接下來,復(fù)制 IInAppBillingService.aidl 文件到您的項(xiàng)目。
    • 如果您使用的是 Android Studio,請(qǐng)執(zhí)行以下操作:
      1. 導(dǎo)航至 Project 工具窗口中的 src/main
      2. 選擇 File > New > Directory,然后在 New Directory 窗口中輸入 aidl,再選擇 OK
      3. 選擇 File > New > Package,然后在 New Package 窗口中輸入 com.android.vending.billing,再選擇 OK
      4. 使用您的操作系統(tǒng)文件資源管理器,導(dǎo)航至 <sdk>/extras/google/play_billing/,復(fù)制 IInAppBillingService.aidl 文件,然后將其粘貼到項(xiàng)目中的 com.android.vending.billing 軟件包。
    • 如果您在非 Android Studio 環(huán)境中開發(fā),請(qǐng)執(zhí)行以下操作:創(chuàng)建目錄 /src/com/android/vending/billing,并將 IInAppBillingService.aidl 文件復(fù)制到此目錄。 將 AIDL 文件添加到您的項(xiàng)目中并使用 Gradle 工具構(gòu)建項(xiàng)目,從而生成 IInAppBillingService.java 文件。
  3. 開發(fā)您的應(yīng)用。您會(huì)在項(xiàng)目的 /gen 目錄中看到名為 IInAppBillingService.java 的生成文件。

更新您的應(yīng)用清單

應(yīng)用內(nèi)購(gòu)買結(jié)算依賴于 Google Play 應(yīng)用,后者將處理應(yīng)用與 Google Play 服務(wù)器之間的所有通信。 要使用 Google Play 應(yīng)用,您的應(yīng)用必須請(qǐng)求適當(dāng)?shù)臋?quán)限。 您可以通過將 com.android.vending.BILLING 權(quán)限添加到 AndroidManifest.xml 文件執(zhí)行此操作。 如果您的應(yīng)用未聲明應(yīng)用內(nèi)購(gòu)買結(jié)算權(quán)限,但試圖發(fā)送結(jié)算請(qǐng)求,Google Play 將拒絕請(qǐng)求并使用錯(cuò)誤響應(yīng)。

要為您的應(yīng)用授予必要的權(quán)限,請(qǐng)?jiān)?AndroidManifest.xml 文件中添加以下代碼行:

<uses-permission  android:name="com.android.vending.BILLING"  />

創(chuàng)建 ServiceConnection

您的應(yīng)用必須擁有 ServiceConnection才能實(shí)現(xiàn)應(yīng)用與 Google Play 之間的通信。 您的應(yīng)用至少需要執(zhí)行以下操作:

  • 綁定到 IInAppBillingService
  • 發(fā)送結(jié)算請(qǐng)求(作為 IPC 方法調(diào)用)至 Google Play 應(yīng)用。
  • 處理每個(gè)結(jié)算請(qǐng)求返回的同步響應(yīng)消息。

綁定到 InAppBillingService

要在 Google Play 上與應(yīng)用內(nèi)購(gòu)買結(jié)算服務(wù)建立連接,請(qǐng)實(shí)現(xiàn) ServiceConnection,以便將您的 Activity 綁定到 IInAppBillingService
建立連接后,重寫 onServiceDisconnected(android.content.ComponentName))onServiceConnected(android.content.ComponentName, android.os.IBinder)) 方法以獲取 IInAppBillingService 實(shí)例的引用。

IInAppBillingService mService;  
ServiceConnection mServiceConn =  new  ServiceConnection()  
{ 
  @Override 
  public  void onServiceDisconnected(ComponentName name)  
  { 
      mService =  null; 
  } 
  @Override 
  public  void onServiceConnected(ComponentName name,  IBinder service)  
  {   
      mService =  IInAppBillingService.Stub.asInterface(service); 
  }  
};

在您 Activity 的 onCreate(android.os.Bundle)) 方法中,通過調(diào)用 bindService(android.content.Intent,android.content.ServiceConnection,int)) 方法執(zhí)行綁定。 向方法傳遞引用應(yīng)用內(nèi)購(gòu)買結(jié)算服務(wù)的 Intent( 和您創(chuàng)建的一個(gè) ServiceConnection 實(shí)例,并明確地將 Intent 的目標(biāo)軟件包名稱設(shè)置為 com.android.vending — Google Play 應(yīng)用的軟件包名稱。

注意:要保護(hù)結(jié)算交易的安全性,請(qǐng)始終確保使用下面示例中所示的 setPackage()(java.lang.String)) 明確地將 Intent 的目標(biāo)軟件包名稱設(shè)置為 com.android.vending。 明確地設(shè)置軟件包名稱能夠確保只有 Google Play 應(yīng)用可以處理來自您的應(yīng)用的結(jié)算請(qǐng)求,從而防止其他應(yīng)用攔截這些請(qǐng)求。

@Override  
public  void onCreate(Bundle savedInstanceState)  
{  
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    Intent serviceIntent =  new  Intent("com.android.vending.billing.InAppBillingService.BIND");           
    serviceIntent.setPackage("com.android.vending"); 
    bindService(serviceIntent, mServiceConn,  Context.BIND_AUTO_CREATE);  
}

現(xiàn)在,您可以使用 mService 引用來與 Google Play 服務(wù)通信。

重要說明:完成您的 Activity 后,請(qǐng)務(wù)必與應(yīng)用內(nèi)購(gòu)買結(jié)算服務(wù)解除綁定。 如果不解除綁定,開啟的服務(wù)連接會(huì)導(dǎo)致您的設(shè)備性能下降。 此示例說明了如何通過重寫 Activity 的 onDestroy() 方法對(duì)到應(yīng)用內(nèi)購(gòu)買結(jié)算的服務(wù)連接 mServiceConn 執(zhí)行解除綁定操作。

@Override  public  void onDestroy() 
 {  
    super.onDestroy(); 
    if  (mService !=  null) 
    { 
     unbindService(mServiceConn); 
    }
}

如需了解綁定到 IInAppBillingService 的服務(wù)連接的完整實(shí)現(xiàn),請(qǐng)參閱[出售應(yīng)用內(nèi)商品]培訓(xùn)課程和相關(guān)示例。

發(fā)起應(yīng)用內(nèi)購(gòu)買結(jié)算請(qǐng)求

將應(yīng)用連接到 Google Play 后,您可以對(duì)應(yīng)用內(nèi)商品發(fā)送購(gòu)買請(qǐng)求。 Google Play 為用戶進(jìn)入他們的付款方式提供了一個(gè)結(jié)賬界面,這樣您的應(yīng)用就無(wú)需直接處理付款交易。 在商品被用戶購(gòu)買后,Google Play 會(huì)識(shí)別用戶擁有此商品,并在此商品被消耗前阻止用戶購(gòu)買具有相同商品 ID 的另一商品。 您可以控制如何在應(yīng)用中消耗商品,并通知 Google Play 該商品可供再次購(gòu)買。 您也可以查詢 Google Play,以便快速地檢索用戶的購(gòu)買列表。 這樣十分有用,例如,非常適合您希望在用戶啟動(dòng)應(yīng)用時(shí)恢復(fù)用戶購(gòu)買的情況。

查詢可供購(gòu)買的商品

在您的應(yīng)用中,可以使用 In-app Billing Version 3 API 從 Google Play 查詢商品詳情。 要將請(qǐng)求傳遞至應(yīng)用內(nèi)購(gòu)買結(jié)算服務(wù),首先需要?jiǎng)?chuàng)建一個(gè)包含商品 ID 字符串 ArrayListBundle,該字符串帶有鍵“ITEM_ID_LIST”,每個(gè)字符串是可購(gòu)買商品的商品 ID。

ArrayList<String> skuList =  new  ArrayList<String>  ();
skuList.add("premiumUpgrade"); 
skuList.add("gas");  
Bundle querySkus =  new  Bundle(); 
querySkus.putStringArrayList(“ITEM_ID_LIST”, skuList);

要從 Google Play 檢索此信息,請(qǐng)?jiān)?In-app Billing Version 3 API 上調(diào)用 getSkuDetails 方法,然后將 In-app Billing API 版本(3)、發(fā)起調(diào)用的應(yīng)用的軟件包名稱、商品類型(應(yīng)用內(nèi))以及您創(chuàng)建的 Bundle 傳遞給方法。

Bundle skuDetails = mService.getSkuDetails(3, getPackageName(),  "inapp", querySkus);

如果請(qǐng)求成功,返回的 Bundle 將包含響應(yīng)代碼 BILLING_RESPONSE_RESULT_OK (0)。

警告:請(qǐng)不要在主線程上調(diào)用 getSkuDetails 方法。 調(diào)用此方法會(huì)觸發(fā)網(wǎng)絡(luò)請(qǐng)求,進(jìn)而阻塞主線程。 請(qǐng)創(chuàng)建單獨(dú)的線程并從該線程內(nèi)部調(diào)用 getSkuDetails 方法。

要從 Google Play 查看所有可能的響應(yīng)代碼,請(qǐng)參閱應(yīng)用內(nèi)購(gòu)買結(jié)算參考

查詢結(jié)果將保存在帶有鍵 DETAILS_LIST 的字符串 ArrayList 中。購(gòu)買信息存儲(chǔ)在 JSON 格式的字符串中。 要查看返回的商品類型詳細(xì)信息,請(qǐng)參閱應(yīng)用內(nèi)購(gòu)買結(jié)算參考

在此示例中,您將從之前代碼段返回的 skuDetails Bundle 中檢索您的應(yīng)用內(nèi)商品的價(jià)格。

int response = skuDetails.getInt("RESPONSE_CODE");  
if  (response ==  0)  {
ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST"); 
for  (String thisResponse : responseList)  {  
    JSONObject  object  =  new  JSONObject(thisResponse); 
    String sku =  object.getString("productId");  
    String price =  object.getString("price");  
    if  (sku.equals("premiumUpgrade")) 
        mPremiumUpgradePrice = price;
   else  if  (sku.equals("gas")) 
       mGasPrice = price; 
   }
}

購(gòu)買商品

要從您的應(yīng)用發(fā)起購(gòu)買請(qǐng)求,請(qǐng)?jiān)趹?yīng)用內(nèi)購(gòu)買結(jié)算服務(wù)上調(diào)用 getBuyIntent 方法。 將 In-app Billing API 版本(3)、發(fā)起調(diào)用的應(yīng)用的軟件包名稱、要購(gòu)買商品的商品 ID、商品類型(應(yīng)用內(nèi)或訂閱)以及 developerPayload 字符串傳遞給方法。 developerPayload 字符串用于指定您想要 Google Play 隨購(gòu)買信息一同發(fā)送的任何其他參數(shù)。

Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(), sku,  "inapp",  "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");

如果請(qǐng)求成功,返回的 Bundle 將包含響應(yīng)代碼 BILLING_RESPONSE_RESULT_OK (0) 和您可以用于開始購(gòu)買流程的 PendingIntent。接下來,請(qǐng)使用鍵 BUY_INTENT 從響應(yīng) Bundle 中提取 `PendingIntent。

PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");

要完成購(gòu)買交易,請(qǐng)調(diào)用 startIntentSenderForResult(android.content.IntentSender,int,android.content.Intent,int,int,int)) 方法并使用您創(chuàng)建的 PendingIntent。 在此示例中,您將任意值 1001 用于請(qǐng)求代碼。

startIntentSenderForResult(pendingIntent.getIntentSender(), 1001,  new  Intent(),  Integer.valueOf(0),  Integer.valueOf(0), Integer.valueOf(0));

Google Play 會(huì)將對(duì)您 PendingIntent 的響應(yīng)發(fā)送至應(yīng)用的 onActivityResult((int,int,android.content.Intent)) 方法。 onActivityResult(int,int,android.content.Intent)) 方法將獲得結(jié)果代碼 Activity.RESULT_OK (1) 或 Activity.RESULT_CANCELED (0)。

訂單的購(gòu)買數(shù)據(jù)是 JSON 格式的字符串,將映射到響應(yīng) Intent 中的 INAPP_PURCHASE_DATA 鍵,例如:

{
   "orderId":"GPA.1234-5678-9012-34567",
   "packageName":"com.example.app",
   "productId":"exampleSku",
   "purchaseTime":1345678900000,
   "purchaseState":0,
   "developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
   "purchaseToken":"opaque-token-up-to-1000-characters" }

:Google Play 會(huì)為購(gòu)買生成令牌。此令牌是不透明的字符序列,最長(zhǎng)可為 1,000 字符。 將整個(gè)令牌傳遞至其他方法(例如在您消耗購(gòu)買時(shí),如消耗購(gòu)買(https://developer.android.com/training/in-app-billing/purchase-iab-products.html?hl=zh-cn#Consume)中所述)。 不要省略或者截?cái)啻肆钆疲仨毐4娌⒎祷卣麄€(gè)令牌。

繼續(xù)前面的示例,您將從響應(yīng) Intent獲得響應(yīng)代碼、購(gòu)買數(shù)據(jù)和簽名。

@Override  
protected  void onActivityResult(int requestCode,  int resultCode,  Intent data)  {
   if  (requestCode ==  1001)  { 
     int responseCode = data.getIntExtra("RESPONSE_CODE",  0);  
     String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");  
     String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");  
     if  (resultCode == RESULT_OK)  {
       try  {  
          JSONObject jo =  new  JSONObject(purchaseData);  
          String sku = jo.getString("productId"); 
          alert("You have bought the "  + sku +  ". Excellent choice,adventurer!"); 
       }  catch  (JSONException e)  { 
         alert("Failed to parse purchase data.");
         e.printStackTrace();  
       }  
     } 
  }  
}

安全性建議:在您發(fā)送購(gòu)買請(qǐng)求時(shí),請(qǐng)創(chuàng)建一個(gè)可以對(duì)此購(gòu)買請(qǐng)求進(jìn)行唯一標(biāo)識(shí)的字符串令牌并在 developerPayload 中包含此令牌。您可以將隨機(jī)生成的字符串作為令牌。 從 Google Play 接收到購(gòu)買響應(yīng)時(shí),請(qǐng)確保檢查返回的數(shù)據(jù)簽名、orderIddeveloperPayload 字符串。 為了增強(qiáng)安全性,您應(yīng)在自己安全的服務(wù)器上執(zhí)行檢查。 請(qǐng)確保驗(yàn)證 orderId 為您之前未處理的唯一值,且 developerPayload 字符串與您之前通過購(gòu)買請(qǐng)求發(fā)送的令牌相匹配。

查詢已購(gòu)買商品

要從您的應(yīng)用檢索用戶所發(fā)起購(gòu)買的相關(guān)信息,請(qǐng)?jiān)趹?yīng)用內(nèi)購(gòu)買結(jié)算版本 3 服務(wù)上調(diào)用 getPurchases 方法。 將 In-app Billing API 版本(3)、發(fā)起調(diào)用的應(yīng)用的軟件包名稱以及商品類型(應(yīng)用內(nèi)或訂閱)傳遞給方法。

Bundle ownedItems = mService.getPurchases(3, getPackageName(),  "inapp",  null);

Google Play 服務(wù)僅會(huì)返回由當(dāng)前登錄設(shè)備的用戶帳戶發(fā)起的購(gòu)買。 如果請(qǐng)求成功,返回的 Bundle 將包含響應(yīng)代碼 0。響應(yīng) Bundle 也會(huì)包含商品 ID 列表、每個(gè)購(gòu)買的訂單詳情列表以及每個(gè)購(gòu)買的簽名。

為了提升性能,第一次調(diào)用 getPurchase 時(shí),應(yīng)用內(nèi)購(gòu)買結(jié)算服務(wù)僅會(huì)返回由用戶擁有的最多 700 個(gè)商品。 如果用戶擁有大量商品,Google Play 會(huì)在響應(yīng) Bundle 中包含映射到鍵 INAPP_CONTINUATION_TOKEN 的字符串令牌,以表明可以檢索更多的商品。 然后,您的應(yīng)用可以進(jìn)行后續(xù) getPurchases 調(diào)用,并將此令牌作為參數(shù)傳遞。 Google Play 會(huì)繼續(xù)在響應(yīng) Bundle 中返回繼續(xù)令牌,直到用戶擁有的所有商品都發(fā)送到您的應(yīng)用。

如需了解有關(guān)由 getPurchases 返回的數(shù)據(jù)的詳細(xì)信息,請(qǐng)參閱應(yīng)用內(nèi)購(gòu)買結(jié)算參考。 下面的示例說明了如何從響應(yīng)中檢索此數(shù)據(jù)。

int response = ownedItems.getInt("RESPONSE_CODE"); 
if  (response ==  0)  { 
  ArrayList<String> ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST"); 
  ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); 
  ArrayList<String> signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); 
  String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN"); 
  for  (int i =  0; i < purchaseDataList.size();  ++i)  {  
    String purchaseData = purchaseDataList.get(i);  
    String signature = signatureList.get(i);  
    String sku = ownedSkus.get(i); 
    // do something with this purchase information  
    // e.g. display the updated list of products owned by user
 }
 // if continuationToken != null, call getPurchases again
 // and pass in the token to retrieve more items  
}

消耗購(gòu)買

您可以使用 In-app Billing Version 3 API 跟蹤在 Google Play 中購(gòu)買的應(yīng)用內(nèi)商品的所有權(quán)。 應(yīng)用內(nèi)商品一經(jīng)購(gòu)買,就會(huì)被視為“被擁有”且無(wú)法從 Google Play 購(gòu)買。 您必須對(duì)應(yīng)用內(nèi)商品發(fā)送消耗請(qǐng)求,然后 Google Play 才能允許再次購(gòu)買。

重要說明:可以消耗托管的應(yīng)用內(nèi)商品,但不能消耗訂閱。

如何在應(yīng)用中使用消耗機(jī)制取決于您。通常情況下,您可以對(duì)用戶想要購(gòu)買多次、能夠提供短期效益的應(yīng)用內(nèi)商品實(shí)現(xiàn)消耗(例如,游戲中使用的貨幣或設(shè)備)。 您通常不必對(duì)僅供購(gòu)買一次和具有永久效應(yīng)的應(yīng)用內(nèi)商品實(shí)現(xiàn)消耗(例如,高級(jí)版升級(jí))。

要記錄購(gòu)買消耗,請(qǐng)將 consumePurchase 方法發(fā)送到應(yīng)用內(nèi)購(gòu)買結(jié)算服務(wù)并在標(biāo)識(shí)要移除購(gòu)買的 purchaseToken 字符串值中傳遞。 purchaseToken 是由購(gòu)買請(qǐng)求成功后 Google Play 服務(wù)在 INAPP_PURCHASE_DATA 字符串中所返回?cái)?shù)據(jù)的一部分。 在此示例中,您會(huì)將使用 purchaseToken 標(biāo)識(shí)的商品的消耗記錄在 token 變量中。

int response = mService.consumePurchase(3, getPackageName(), token);

警告:請(qǐng)不要在主線程上調(diào)用 consumePurchase 方法。 調(diào)用此方法會(huì)觸發(fā)網(wǎng)絡(luò)請(qǐng)求,進(jìn)而阻塞主線程。 請(qǐng)創(chuàng)建單獨(dú)的線程并從該線程內(nèi)部調(diào)用 consumePurchase 方法。

您負(fù)責(zé)控制和跟蹤如何向用戶配置應(yīng)用內(nèi)商品。 例如,如果用戶購(gòu)買了游戲內(nèi)貨幣,您應(yīng)使用購(gòu)買的貨幣金額更新玩家的庫(kù)存。

安全性建議:您必須首先發(fā)送消耗請(qǐng)求,才能向用戶配置可消耗的應(yīng)用內(nèi)購(gòu)買商品。 確保已從 Google Play 接收到成功的消耗請(qǐng)求,然后再配置商品。

實(shí)現(xiàn)訂閱

啟動(dòng)訂閱的購(gòu)買流程與啟動(dòng)商品的購(gòu)買流程相似,不同之處是商品類型必須設(shè)置為“訂閱”。 購(gòu)買結(jié)果會(huì)傳送至您 Activity 的onActivityResult(int,int,android.content.Intent)) 方法,與應(yīng)用內(nèi)商品的情況完全一樣。

Bundle bundle = mService.getBuyIntent(3,  "com.example.myapp", MY_SKU,  "subs", developerPayload);  
PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT);  
if  (bundle.getInt(RESPONSE_CODE)  == BILLING_RESPONSE_RESULT_OK)  
{
   // Start purchase flow (this brings up the Google Play UI). 
  // Result will be delivered through onActivityResult(). 
  startIntentSenderForResult(pendingIntent, RC_BUY,  new  Intent(), Integer.valueOf(0),  Integer.valueOf(0),  Integer.valueOf(0)); 
 }

要查詢有效訂閱,請(qǐng)使用 getPurchases 方法,并將商品類型參數(shù)設(shè)置為“訂閱”。

Bundle activeSubs = mService.getPurchases(3,  "com.example.myapp", "subs", continueToken);

調(diào)用會(huì)返回 Bundle,其包含由用戶擁有的所有有效訂閱。 如果訂閱到期且不續(xù)訂,將不會(huì)出現(xiàn)在返回的 Bundle 中。

保證您的應(yīng)用安全

為了確保發(fā)送到您應(yīng)用的交易信息的完整性,Google Play 會(huì)簽署包含購(gòu)買訂單響應(yīng)數(shù)據(jù)的 JSON 字符串。 Google Play 會(huì)使用 Developer Console 中與您的應(yīng)用關(guān)聯(lián)的私鑰來創(chuàng)建此簽名。 Developer Console 會(huì)為每個(gè)應(yīng)用生成一個(gè) RSA 密鑰對(duì)。

:要找到此密鑰對(duì)的公鑰部分,請(qǐng)?jiān)?Developer Console 中打開應(yīng)用的詳細(xì)信息,然后點(diǎn)擊 Services & APIs,并查看命名為 Your License Key for This Application 的字段。

由 Google Play 生成的以 Base64 編碼的 RSA 公鑰為二進(jìn)制編碼,格式為 X.509 subjectPublicKeyInfo DER SEQUENCE。 它與 Google Play 許可使用的公鑰相同。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,814評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,224評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,444評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,804評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,998評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評(píng)論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,237評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評(píng)論 1 287
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,706評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,993評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,662評(píng)論 25 708
  • 記憶里姥姥總是和藹可親,從來都是我和弟弟的保護(hù)傘,每次面臨爸媽棍棒威脅的時(shí)候,躲到姥姥身邊總能平安無(wú)事。但...
    舒文shuwen閱讀 474評(píng)論 2 6
  • 最開安利《老九門》這部劇,純粹是刷臉來的,確實(shí)沒看過三叔的原著,對(duì)于這些盜墓類的題材,想來能連著追VIP,恐怕也都...
    尚武三寶閱讀 2,866評(píng)論 0 0
  • 你放不下的不是我,是這段時(shí)光,還有校園里可愛的小伙伴們和美女老師,不過喜歡我,會(huì)多一點(diǎn)。
    好生歡喜陶陶陶閱讀 154評(píng)論 0 0
  • 秋街落雪了隔著好些童年的距離紅色的圍巾尚未織完柴火不曾成炭永生的庭院走入暮色被注視的,依舊失語(yǔ) 少女藏謎被夕陽(yáng)追逐...
    2020號(hào)閱讀 1,654評(píng)論 9 51