2014年4月28日 星期一

Common Errors in Google In-App Billing

前一陣子接觸了 Google Play 的 IAB 串接,測試途中發生幾次小卡關,由於同時間和 iOS 團隊皆在同個產品中實作應用程式內付費功能,從這個經驗中也順便看到了兩個平台的差異,寫篇文章來記錄一下 IAB 的概念及常見錯誤處理方式。

在 Android 上叫 IAB 的東西在 iOS 上叫 IAP (In-App Purchase),在 Windows Phone 上也是叫 IAP,查詢資料時需注意一下有沒有打錯,Google IAB 文件可以參考:Billing

實作 IAB 功能前,必須先透過 SDK Manager 在 Extras 內勾選安裝並加入 Google Play Billing Library,在安裝完後的 play_billing 目錄下可以找到官方的範例,官方的範例中有一個包裝好的 Utility tool 叫 iabHelper,這個 iabHelper 幾乎將所有實作程式內購買需要用到的 API 都包裝成很簡易使用的 Method,非常適合初學者學習入門,但是,直接拿這個 iabHelper 來使用卻是一件非常不被建議的行為,通常用戶購買的資料是屬於被公司保護的財產,或牽涉到版權的數位內容,如果直接使用 iabHelper 等於是讓透過逆向工程找到相關程式碼的難度大幅縮減,故還是建議開發者能夠了解細節的 API。

Google Play 對於程式內商品的分類為以下三種
1. 未納入管理的商品
2. 納入管理的商品
3. 訂閱型商品

大致上 1 與 2 是一樣的東西,差別在於如果商品是未納入管理的,Google 不會記錄任何用戶的交易資料,必須由開發者自行管理交易資料,而納入管理的商品則會被 Google 記錄,用戶及開發者皆可以在 Google 的介面查到每一筆交易記錄。

對於使用新版 SDK ( Version 3 ) 的開發者而言,所有的商品皆要納入管理故無法建立第 1 種類型的商品,以第 1、2 種商品而言,常見的實例是遊戲中的藥水或寶石,納入管理的商品雖然提供了查詢的便利性,但對開發者而言是否納入管理代表著是否需要處理額外的手續。

未納入管理的商品用戶在購買完後可以立即再接著購買,不必等待任何狀態的改變,但納入管理的商品於用戶再次購買時,Google 會提示用戶已經擁有該商品了而拒絕用戶的再次購買行為,若接受用戶重覆購買此類商品,開發者必須再利用 consumePurchase 將該購買記錄標示為已消耗完畢,用戶才可以繼續購買,相對的,如果某些商品真的只能讓用戶購買一次,就不需要額外調用 consumePurchase。

第 3 種訂閱型商品在建立產品時,可以建立為每月自動訂閱或每年自動訂閱,用戶在購買後讓記錄會顯示在 Google Play 的 App 資訊頁上,並且由 Google Play Service 來處理每月或每年的扣款動作,用戶也可以透過 Google Play 頁面來退訂,在最後一次訂閱的週期過後即會生效。

以下是五個 IAB 主要行為的 Method

isBillingSupported:此應用程式是否支持 IAB
getSkuDetails:使用 product id 取得商品詳細資訊,SKU = Stock Keeping Unit
getPurchases:向 Play Service 詢問程式內商品的購買狀態
getBuyIntent:向 Play Service 取得購買某項商品的 Intent 以開始進行購買
consumePurchase:向 Play Service 發出某商品已消耗的指令

由上面的清單可以發現,Google 官方並沒有提供查詢應用程式內商品清單的 API,所以必須開發者自行管理商品 Id 列表,且如果販售的資料是文字或圖片等容量較小的數位內容,依然建議將資料放在自行管理的 Server 上,而不是包在 apk 內的 resource 或 database 中,否則其實蠻容易在用戶未購買的情況下利用逆向工程取出數位內容,當然程式碼的混淆也是必須進行的動作,如果是使用 ProGuard 做混淆,需要特別注意加上這行

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

再來有一個需注意的是使用 Billing Library 時,概念和一般的 Library 不同,Billing Library 主要是透過 IInAppBillingService.aidl
 與 Google Play Service 做溝通,所以並沒有所謂的 SDK 或 jar 檔案需要參考,另一層的意思是,在某些特殊的手機有可能沒有 Google Play Application 而只有廠商自家的商城,此類手機是沒辦法執行應用程式內購買行為的,必須自行判斷 Play Package 是否存在。

在使用 IInAppBillingService.aidl 時,官方的文件所描述的是使用 Eclipse + ADT 開發的檔案位置,若是使用 Android Sutdio 開發,這個檔案的放置目錄是不一樣的,必須放在 app/src/main/aidl/com/android/vending/billing 資料夾底下,相關資訊可以參考這裡:TOC-Project-Structure

應用程式內購買的相關流程實作完成後,最快面臨到的問題就是如何測試,官方提供了兩種方式可供測試,一種叫 Testing with Static Responses,另一種方式是 Setting Up for Test Purchases。

Testing with Static Responses 指的是送出特殊的 Product Id 執行購買流程,這種情況下 Google Play Service 會回傳固定的 Response 給開發者,開發者即可以利用這種方式測試各種狀況的例外處理流程是否合適,特殊的 Product Id 如下

android.test.purchased
android.test.canceled
android.test.refunded
android.test.item_unavailable

而 Setting Up for Test Purchases 指的是在 Google developer console 中將某些 Google Account 加入測試人員清單中,那麼這些帳號在該 App 內進行購買行為時是不會被扣款的,訂單將在 14 天後自動取消,需要注意一點,開發者自己的 Google Account 是沒辦法成為測試人員的,所以除了開發者帳號之外,還要額外準備一個已綁信用卡的 Google Account 來做測試,進行測試時其他常見的錯誤還有

1. 錯誤訊息 "內容發佈者無法購買這項商品"
這在文件上有說明:You cannot use your developer account to test the complete in-app purchase process because Google Wallet does not let you buy items from yourself

2. 錯誤訊息 "應用程式未提供google play結帳功能"
注意一下你測試中的 apk 是否與上架的 apk 使用了不同的 sing key,若不相同是無法測試的,除了 sign key 必須一致之外,還要注意 Application version 是否相同,測試的 apk 必須與架上的 apk 版號是一致的,否則也是無法測試。

沒有留言:

張貼留言