1. 程式人生 > >Google Play支付接入(in-app Billing)

Google Play支付接入(in-app Billing)

Google Play in-app Billing的接入過程需要閱讀接入文件。官方的接入文件地址為:

(1)Google Play開發者控制檯

Google Play開發者控制檯是管理應用,配置商品和釋出的後臺。參考地址為:

Google Play的幫助文件地址為:

使用步驟:

1. 註冊Google Play開發者帳號

Google Play開發者帳號註冊地址為:(需支付25美元的註冊費,支援Visa信用卡等支付。)

2. 配置應用商品,獲取客戶端接入引數,步驟簡述如下:

在Google Play後臺建立應用,設定遊戲名稱。按照要求填寫商品詳情。上傳APK,注意上傳的APK必須是release簽名的正式包,同時要匹配好包名和版本號,然後再配置商品品項。獲取Google Play的接入公鑰(Base64編碼的RSA公共金鑰)。

受管理的商品:每個帳號只能購買一次,不能重複購買的商品。例如:啟用碼、解鎖關卡等。

不受管理的商品:該商品可重複購買。包含支付完須消費,沒消費的不可能重複購買,這步對消費者是透明的。例如:金幣、鑽石等。

訂閱:通過按月或按年結算的方式在應用內向使用者銷售內容、服務或功能。

3. 獲取服務端接入引數

支付完成之後,需要在服務端校驗支付的票據是否合法。同樣,也需要獲取服務端引數。步驟如下:
(1)使用建立應用的開發者帳號,進入Google API管理後臺。地址如下:

(2)確認是否啟用了Google Play Android Developer API。若未啟用,則點啟用。

(3)配置OAuth,填寫郵件地址和產品名稱,並儲存。

(4)建立客戶端OAuth id。

(5)在新介面中,選擇網頁應用。並配置授權地址和重定向地址,並點選建立。

(6)獲取客戶端id和客戶端金鑰。

(7)回到在Google Play後臺啟用API。確保一個關聯和一個啟用狀態。

(9)再利用獲取到的code,獲取refresh_token引數。
用post請求如下地址,注意引數:code=XXX&client_id=XXX&client_secret=XXX&redirect_uri=http://www.example.com/oauth2callback&grant_type=authorization_code

,其中grant_type為固定值。

得到json:

   {  
       "access_token" : "ya29.dAFAF9xX89iR4s0Li4_faSmtGFonWQz67HvfXZFkPWsY_tHI_q1c7fc6WTS9EqKMi7_wonxhp4Q2FA",  
       "token_type" : "Bearer",  
       "expires_in" : 3600,  
       "refresh_token" : "XXX"  
   }

這樣便獲得了refresh_token引數。
伺服器校驗的時候,便可以通過refresh_token,來獲取access_token等。

(2)Google Play in-app Billing購買流程

這裡我就直接從Google Play官方文件摘取過來購買流程的內容,方便查詢。

1. 購買流程

先熟悉下V3版本的購買流程,知道大體的支付步驟和實現邏輯。如圖:

(1) 您的應用向 Google Play 傳送 isBillingSupported 請求,以確定您當前使用的應用內結算 API 目標版本是否受支援。

(2) 當您的應用啟動或使用者登入時,最好向 Google Play 進行查詢,確定該使用者擁有哪些商品。要查詢使用者的應用內購買,請傳送 getPurchases 請求。如果該請求成功,Google Play 會返回一個 Bundle,其中包含所購商品的商品 ID 列表、各項購買詳情的列表以及購買簽名的列表。

(3) 通常情況下,您需要通知使用者商品是否可供購買。要查詢您在 Google Play 中定義的應用內商品的詳細資訊,應用可以傳送 getSkuDetails 請求。您必須在該查詢請求中指定商品 ID 列表。如果該請求成功,Google Play 會返回一個包含產品詳情(包括商品的價格、標題、說明和購買型別)的 Bundle

(4) 如果該使用者還未擁有應用內商品,您可以提示購買。為了發起購買請求,您的應用會發送 getBuyIntent 請求,指定要購買商品的商品 ID 以及其他引數。當您在開發者控制檯中建立新的應用內商品時,應記錄其商品 ID。

Google Play 返回的 Bundle 中包含 PendingIntent,您的應用可用它來啟動購買結帳介面。

您的應用通過呼叫 startIntentSenderForResult 方法來啟動 PendingIntent

當結帳流程結束後(即使用者成功購買商品或取消購買),Google Play 會向您的 onActivityResult 方法傳送響應 Intent。onActivityResult 的結果程式碼中有一個程式碼將用於表明使用者是完成了購買還是取消了購買。響應 Intent 中會包含所購商品的相關資訊,其中包括 Google Play 為了唯一識此次購買交易而生成的 purchaseToken 字串。Intent 中還包含使用您的私人開發者金鑰簽署的購買簽名。

2. 消耗流程

Google Play的支付分為購買-消耗兩步。如果是在Google Play後臺配置的商品品項是受管理型別的商品,則只需要呼叫購買即可,即不可重複購買。如果配置的是不受管理型別的商品,則在購買成功回撥裡要手動呼叫下消耗介面,否則該商品不能重複購買。
消耗

在第 3 版中,所有應用內商品都是託管的。也就是說,使用者對所購應用內商品的所有權由 Google Play 進行維護,您的應用可以在需要時查詢使用者的購買資訊。當用戶成功購買應用內商品後,該次購買就會記錄在 Google Play 中。應用內商品一經售出,就會被視為“被擁有”。處於“被擁有”狀態的應用內商品無法再通過 Google Play 購買。您必須對“被擁有”的應用內商品傳送消耗請求,然後 Google Play 才能再次將其設成可購買狀態。消耗應用內商品會將商品切換回“未被擁有”狀態並刪除之前的購買資料。

為了檢索使用者所擁有商品的列表,您的應用會向 Google Play 傳送 getPurchases 呼叫。您的應用可以通過傳送 consumePurchase 呼叫提出消耗請求。在請求引數中,您必須指定應用內商品獨一無二的 purchaseToken 字串,此字串是在商品售出時由 Google Play 指定的。Google Play 會返回一個狀態程式碼,指明此次消耗是否已成功記錄。

(1)呼叫 getBuyIntent 啟動購買流程。
(2)從 Google Play 接收指示購買是否成功完成的響應 Bundle
(3)如果購買成功,通過呼叫 consumePurchase 消耗此次購買。
(4)從 Google Play 接收指示消耗是否成功完成的響應程式碼。
(5)如果消耗成功,在應用中配置商品。

以上是購買到消耗的整個流程,這麼複雜的購買流程到程式碼層該如何實現了。還好我們可以通過取巧的辦法,用Google Play給我們提供的Samples中程式碼“拿來即用”,節省開發週期。

(3)Google Play in-app Billing api接入

1. 下載Google Play Billing Library

開啟ANdroid SDK Manager。在extras中勾選Google Play Billing Library和Google Play Service。如圖:

下載完的Library路徑應該會在<android-sdk-root>/extras/google/play_billing。目錄結構如圖:

並匯入samples到Eclipse中。用AndroidStudio也類似,這裡主要介紹下Eclipse的操作步驟。

2. 將samples對應的程式碼直接拷貝到自己的專案中。如圖:

3. 在AndroidManifest中新增如下許可權:

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

4. 初始化in-app Billing api。直接把以下程式碼放到合適的地方,一般是主Activity的onCreate中。IabHelper是一個封裝了購買-消耗的個工具類,queryInventoryAsync是訂單查詢方法。注意替換實際的公鑰(Google Play後臺建立應用裡,在服務和API這項可以找到,一串Base64編碼的字串)。

    // base64EncodedPublicKey為Base64編碼RSA公共金鑰
    String base64EncodedPublicKey = "CONSTRUCT_YOUR_KEY_AND_PLACE_IT_HERE";
    // Create the helper, passing it our context and the public key to verify signatures with
    Log.d(TAG, "Creating IAB helper.");
    mHelper = new IabHelper(this, base64EncodedPublicKey);

    // enable debug logging (for a production application, you should set this to false).
    mHelper.enableDebugLogging(true);

    // Start setup. This is asynchronous and the specified listener
    // will be called once setup completes.
    Log.d(TAG, "Starting setup.");
    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
        public void onIabSetupFinished(IabResult result) {
            Log.d(TAG, "Setup finished.");

            if (!result.isSuccess()) {
                // Oh noes, there was a problem.
                return;
            }

            // Have we been disposed of in the meantime? If so, quit.
            if (mHelper == null) return;

            // IAB is fully set up. Now, let's get an inventory of stuff we own.
            Log.d(TAG, "Setup successful. Querying inventory.");
            mHelper.queryInventoryAsync(mGotInventoryListener);
        }
    });

5. 支付。在發起購買請求的時候,呼叫以下程式碼。sku引數為對應Google Play後臺配置的商品品項id。extraData可用於透傳引數

   IabHelper.launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener, String extraData)

6. 消耗。一般是在支付成功或查詢成功的回撥裡呼叫消費方法。

注意:不受管理的商品,在支付完需要呼叫消費。不然,沒法重複購買。測試帳號返回的票據中不帶orderId。

   IabHelper.consumeAsync(Purchase purchase, OnConsumeFinishedListener listener)

7. 查詢。在查詢回撥裡,檢測如果存在支付但沒消費的商品,繼續呼叫消費。可用於漏單處理。直接放在IapHelper初始化中即可。

   IabHelper.queryInventoryAsync(QueryInventoryFinishedListener listener)

8. 銷燬。一般是在主Activity的onDestory裡執行。

    public void onDestroy() {
        super.onDestroy();
    
        // very important:
        Log.d(TAG, "Destroying helper.");
        if (mHelper != null) mHelper.dispose();
        mHelper = null;
    }

(4)測試Google Play in-app Billing api的接入

1. 測試機上安裝Google框架

國內的手機一般需要手動安裝Google框架(Google Play商店,Google Play Service等),這裡推薦個“谷歌安裝器”的app。安裝這個app可以自動檢測手機內缺少哪些Google服務。不過,安裝“谷歌安裝器”部分手機需要Root許可權。
下載谷歌安裝器。當然,安裝完Google框架還需要VPN,能FQ,正常開啟Google Play商店。

2. 安裝接入好Google Play in-app Billing的app到手機

前面提到,測試Google Play in-app Billing的接入,須包名,版本好跟上傳的一致,而且簽名必須是release簽名的。這樣我們可以將release簽名檔案修改為預設的簽名,方便我們除錯。直接連手機執行,省去了每次打包再安裝到手機

(1)先備份正式的簽名檔案。然後,在Windows命令列視窗中修改keystore密碼為android。
keytool -storepasswd -keystore test.keystore
先輸入原簽名檔案的密碼,再輸入新密碼為android。
(2)修改原簽名檔案的alias,修改為androiddebugkey。
keytool -changealias -keystore test.keystore -alias test -destalias androiddebugkey
test為原簽名檔案的alias,修改為androiddebugkey
這步會要求輸入keystore的密碼(即:android)和當前alias的密碼
(3)修改alias密碼
keytool -keypasswd -keystore my.keystore -alias androiddebugkey
這步會要求輸入keystore密碼(即:android)和原alias密碼,然後在輸入新的alias密碼,輸入android即可。
(4)Eclipse中指定預設的簽名
選擇Window->Preferences->Android->Build->Browse,選擇剛製作的簽名檔案即可。這樣,就可以直接連手機除錯運行了。

3. 新增測試帳號

在Google Play後臺上傳Alpha版測試或Beta測試版裡新增測試人員帳號。
(1)建立Google+群
邀請測試人員加入Google+群組的方式,邀請會收到郵件,不過邀請大概會有4小時延遲。

(2)分享測試連線
將形如以下連線分享給測試者,測試者開啟連線加入測試。“org.cocos2d.game”為應用對應的包名。

(5)接入常見問題

1. 無法購買您要買的商品。

當前Google Play帳號不是測試帳號

2. 需要驗證身份。您需要登入自己的Google帳號。

本地測試的版本號和google上傳的版本號要一致

3. Cannot load library: soinfo_relocate(linker.cpp:993): cannot locate symbol "signal"

05-05 19:08:32.148: E/AndroidRuntime(7822): FATAL EXCEPTION: main
05-05 19:08:32.148: E/AndroidRuntime(7822): java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_relocate(linker.cpp:993): cannot locate symbol "signal" referenced by "libcocos2dlua.so"...
05-05 19:08:32.148: E/AndroidRuntime(7822): at java.lang.Runtime.loadLibrary(Runtime.java:372)
05-05 19:08:32.148: E/AndroidRuntime(7822): at java.lang.System.loadLibrary(System.java:514)
05-05 19:08:32.148: E/AndroidRuntime(7822): at org.cocos2dx.lib.Cocos2dxActivity.onLoadNativeLibraries(Cocos2dxActivity.java:113)
05-05 19:08:32.148: E/AndroidRuntime(7822): at org.cocos2dx.lib.Cocos2dxActivity.onCreate(Cocos2dxActivity.java:128)
05-05 19:08:32.148: E/AndroidRuntime(7822): at org.cocos2dx.lua.AppActivity.onCreate(AppActivity.java:90)
05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.Activity.performCreate(Activity.java:5226)
05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1151)
05-05 19:08:32.148: E/AndroidRuntime(7822): at com.lbe.security.service.core.client.b.x.callActivityOnCreate(Unknown Source)
05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2360)
05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2448)
05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread.access$600(ActivityThread.java:173)
05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1392)
05-05 19:08:32.148: E/AndroidRuntime(7822): at android.os.Handler.dispatchMessage(Handler.java:107)
05-05 19:08:32.148: E/AndroidRuntime(7822): at android.os.Looper.loop(Looper.java:194)
05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread.main(ActivityThread.java:5469)
05-05 19:08:32.148: E/AndroidRuntime(7822): at java.lang.reflect.Method.invokeNative(Native Method)
05-05 19:08:32.148: E/AndroidRuntime(7822): at java.lang.reflect.Method.invoke(Method.java:525)
05-05 19:08:32.148: E/AndroidRuntime(7822): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:857)
05-05 19:08:32.148: E/AndroidRuntime(7822): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
05-05 19:08:32.148: E/AndroidRuntime(7822): at dalvik.system.NativeStart.main(Native Method)

Application.mk新增:APP_PLATFORM := android-17

4. 此版本的應用為配置為通過Google Play結算。有關詳情,請訪問幫助中心。

檢查下打包所用的簽名與上傳Google Play後臺的簽名是否一直。

5. In-app billing error: Purchase signature verification FAILED

程式碼中base64EncodedPublicKey引數不正確,跟Google後臺的不一致。

6. IabResult: Error checking for billing v3 support. (response: 3:Billing Unavailable)

在手機的設定裡需建立並登入Google賬號。