實現內購計費
傻逼目錄
-
Adding the AIDL file
- Updating Your Manifest
- Creating a ServiceConnection
- Making In-app Billing Requests
-
Querying Items Available for Purchase
- Purchasing an Item
- Querying Purchased Items
- Consuming a Purchase
- Implementing Subscriptions
- Securing Your App
二逼參考
-
In-app Billing Reference (V3)
根本無法執行的例子
-
Sample Application (V3)
也看
-
Selling In-app Products
Google Play 的 In-app Billing 提供了一種直(hui)觀(se)簡(nan)單(dong)的接口, 提供向GooglePlay發送內購請求和管理GooglePlay內購交易的功能。這都基於V3版本的API
測試你的程序的教程,參見 Selling In-app Products 訓練課程. 教程提供了完整的內購示例。
包含方便的類庫,用於從google play設置你的連接,發送賬單,購買響應,以及管理后台線程讓你可以在主線程調用內購。
在此之前,確保你閱讀了 In-app Billing Overview 以了解內購的基本概念,讓你更容易實現內購。
實現內購,你需要
- IInAppBillingService庫文件植入你的項目
- AndroidManifest.xml 文件
- ServiceConnection 並綁定到
IInAppBillingService
. - 添加 AIDL 文件到你的工程
是一個
Android Interface Definition Language (AIDL) 文件他定義了V3版內購服務的接口,你可以使用這些接口,通過IPC方法的方式調用函式,創建賬單請求
獲取ADIL:
- Android SDK Manager.
- Extras 段
- 選擇Google Play Billing Library.
- 點擊Install packages 完成下載
sdk/extras/google/play_billing/
.
具體來說:
- 首先,下載 Google Play Billing Library到你的安卓工程
-
Tools > Android > SDK Manager.(2.0版AS-File->Settings)
- SDK Tools 子頁下載下一步,拷貝
文件到你的工
-
原文都是垃圾,直接創建src/com/android/vending/billing/
- 把文件考進去,拉倒。
- 原文說需要Gradle編譯,沒有也一樣,直接打個APK試試,對應文件就會自己生成!
編譯你的工程.編譯出
IInAppBillingService.java
需要用gradle編譯一下,但是已經編好的也可以直接拿過來用(別聽他的!)。(重要的事情說3遍,Unity用戶請不要用AS,用Eclipse)X3。
- SDK Tools 子頁下載下一步,拷貝
更新你的 App的 Manifest
更新你的 App的 Manifest
不翻譯了,廢話那么多,直接加上這句拉倒
<uses-permissionandroid:name="com.android.vending.BILLING"/>
創建一個 ServiceConnection
創建一個 ServiceConnection
你的APP必須有一個 ServiceConnection
來協助你的APP和GooglePlay之間的消息傳遞,至少你應該:
為了和GooglePlay上的內購服務建立連接,你需要實現一個 ServiceConnection
並把你的Activity綁定到IInAppBillingService
.
重寫onServiceDisconnected
和 onServiceConnected
方法,在建立連接后獲得IInAppBillingService
實例的引用
IInAppBillingService mService;
ServiceConnection mServiceConn =newServiceConnection(){
@Override
publicvoid onServiceDisconnected(ComponentName name){
=null;
}
@Override
publicvoid onServiceConnected(ComponentName name,
IBinder service){
=IInAppBillingService.Stub.asInterface(service);
}
};
onCreate
方法中,調用 bindService
方法綁定. 把 Intent
傳給方法,他代表內購服務。再傳入一個你剛剛創建的 ServiceConnection
的實例,並且顯式的設定你的Intent的包名為 使用如下所示的
setPackage()
方法時刻確保顯示的設置intent的目標包名為@Override
publicvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
(R.layout.activity_main);
Intent serviceIntent =
newIntent("com.android.vending.billing.InAppBillingService.BIND");
.setPackage("com.android.vending");
(serviceIntent, mServiceConn,Context.BIND_AUTO_CREATE);
}
現在你可以使用mService的引用去和GooglePlay Service通信了。
重要: 當你的Activity嗝屁的時候記住對你的mService解綁。不然他會讓你的(其實是用戶的,不關你屁事)設備變慢。如何解綁看下面:
@Override
publicvoid onDestroy(){
super.onDestroy();
if(mService !=null){
(mServiceConn);
}
}
(沒讓你看JJ,看上面的代碼塊)
全套實現Selling In-app Products 訓練課程,和附件例子。
創建In-app Billing請求
創建In-app Billing請求
一旦你的應用程序連接到 Google Play, 你就可以初始化內購商品了。 GooglePlay提供了校驗接口,使用戶可以進入他們的支付方法,所以你的應用程序不必自己處理支付事務。
當一個物品被購買,GooglePlay會識別這個用戶對那個物品的所有權,並且防止他購買相同id的產品,直到這個物件被消費掉。
你可以在你的APP里面控制物品如何被消耗掉(通常買了就應該馬上消耗掉,這樣客戶才能再買),並通知GooglePlay,那個商品可以被再次購買。
你也可以快速的向GooglePlay查詢為用戶建立的物品購買清單。這很有用,例如,當你的用戶啟動APP時,你可能需要為他恢復購買。
為購買查詢可購買商品
為購買查詢可購買商品
在你的APP里,你可以利用V3內購API向GooglePlay查詢商品的細節。你需要把一個請求發給In-app Billing 服務。
首先創建一個Bundle
他包含一個記錄商品ID的,鍵值為"ITEM_ID_LIST"的字符串 ArrayList列表
, 每一個ID都是一個可購買商品。
ArrayList<String> skuList =newArrayList<String>();
.add("premiumUpgrade");
.add("gas");
Bundle querySkus =newBundle();
.putStringArrayList(“ITEM_ID_LIST”, skuList);
getSkuDetails
方法,
getPackageName()
Bundle skuDetails = mService.getSkuDetails(3,
(),"inapp", querySkus);
如果請求成功,返回的bundle將會有返回值代碼 BILLING_RESPONSE_RESULT_OK
(0).
getSkuDetails
方法. 調用這個方法會觸發一個網絡請求並阻塞主線程。
作為替代,創建一個單獨線程,並在其中調用getSkuDetails
。(不會Java,你倒是說說怎么創建線程)
如果你想指定所有的可能的返回代碼的意義,去看 In-app Billing Reference.(我不知道,也不想知道!)
查詢結果被存在一個key為DETAILS_LIST的字符串ArrayList中。購買信息以字符串形式存於JSON格式中。
想要獲取返回的產品細節信息,參照 In-app Billing Reference.
在這個例子中,你從前面代碼塊里創建的skuDetails 這個bundle里面,取得你的內購商品價格。
int response = skuDetails.getInt("RESPONSE_CODE");
if(response ==0){
ArrayList<String> responseList
= skuDetails.getStringArrayList("DETAILS_LIST");
for(String thisResponse : responseList){
JSONObjectobject=newJSONObject(thisResponse);
String sku =object.getString("productId");
String price =object.getString("price");
if(sku.equals("premiumUpgrade")) mPremiumUpgradePrice = price;
elseif(sku.equals("gas")) mGasPrice = price;
}
}
PS:估計你得自己搞一張CSV表,或其他什么的,存放你的商品,然后對應返回信息,來更新UI,顯示給玩家。客戶端有而服務器不存在的商品,或被下架的商品,是不應該顯示給玩家的。
購買一個商品
Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
,"inapp","bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
Bundle
會有返回值代碼 BILLING_RESPONSE_RESULT_OK
(0) 和一個 PendingIntent
(這又是啥逼玩意啊!)你可以用他們啟動一個購買流程。
BUY_INTENT從返回的Bundle
提取 PendingIntent
.
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
想要完成購買事務,需要調用 startIntentSenderForResult
方法,並使用之前創建的 PendingIntent
。在這個栗子里面,你使用一個隨意的值1001作為請求碼。
startIntentSenderForResult(pendingIntent.getIntentSender(),
1001,newIntent(),Integer.valueOf(0),Integer.valueOf(0),
Integer.valueOf(0));
PendingIntent 到你的APP的 onActivityResult
方法中。 onActivityResult
方法會得到一個返回值為Activity.RESULT_OK
(1) 或Intent
中全部返回訂單 的信息,訪問 In-app Billing Reference.
INAPP_PURCHASE_DATA 鍵值,在返回 Intent中
,舉個栗子:
'{
"opaque-token-up-to-1000-characters"
}'
此令牌是一個不可讀的字符序列,最長1000個字符. 將這個令牌整個傳入其他方法,比如當你想消耗購買時,正如 Consume a Purchase. 中提到的。不要省略或者改變令牌的大小寫,你需要保存整個令牌。
Intent的簽名。
@Override
protectedvoid 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 =newJSONObject(purchaseData);
String sku = jo.getString("productId");
("You have bought the "+ sku +". Excellent choice,
);
}
catch(JSONException e){
("Failed to parse purchase data.");
.printStackTrace();
}
}
}
}
developerPayload中,你可以隨機的生成一個字符串令牌。
當你從GooglePlay獲取購買響應,確保驗證返回數據的前面,orderId和developerPayload
字符串。
附加的安全性:你應該在你自己的安全服務器上,檢測這些東西。
確保你的orderId是一個你之前沒用過的唯一值。並且developerPayload
字符串和你之前隨購買請求發送的令牌相互匹配。
查詢已購商品
getPurchases
方法。參數傳入版號3,包名和“inapp”類別(訂閱為“subs”)
Bundle ownedItems = mService.getPurchases(3, getPackageName(),"inapp",null);
Bundle 返回代碼0.
Bundle 同時也包含一個產品IDs列表,標記每一個產品的細節和簽名。
getPurchase 調用順序為基准。
Bundle 會返回INAPP_CONTINUATION_TOKEN
暗示還有更多的商品可以獲得。你可以用這個token作為參數,進行后續的getPurchases
請求。
int response = ownedItems.getInt("RESPONSE_CODE");
if(response ==0){
ArrayList<String> ownedSkus =
.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
ArrayList<String> purchaseDataList =
.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
ArrayList<String> signatureList =
.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
String continuationToken =
.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);
}
}
消耗一個購買
purchaseToken
作為參數傳入。
INAPP_PURCHASE_DATA 返回的字符串包含了這次要用的purchaseToken
,他在token變量里面,這就是為什么上面的說明要求你自己記錄token。
int response = mService.consumePurchase(3, getPackageName(), token);
警告: 別在主線程調用這個方法,建立獨立的子線程干這個事。否則他會阻塞你的主線程。
MY_SKU,"subs", developerPayload);
PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT);
if(bundle.getInt(RESPONSE_CODE)== BILLING_RESPONSE_RESULT_OK){
(pendingIntent, RC_BUY,newIntent(),
Integer.valueOf(0),Integer.valueOf(0),Integer.valueOf(0));
}
Bundle activeSubs = mService.getPurchases(3,"com.example.myapp",
"subs", continueToken);
在 Developer Console,打開你的application's details,然后點擊Your License Key for This Application.
由狗狗Play生成的 Base64-encoded RSA 公鑰使用二進制編碼, X.509 subjectPublicKeyInfo DER SEQUENCE 格式. 他與狗狗Play的許可是同一級別的。