Administering In-app Billing
Security and Design
AndroidManifest.xml中必須增加底下宣告:
<uses-permission android:name="com.android.vending.BILLING" />Package的名稱必須Rename,
package com.wsj.android.trivialdrivesample;換入你上傳App後的金鑰,
String base64EncodedPublicKey = "MIIBIjANBgkqhkiG9w0B...省略.....";Google Play Console中,產生程式中購買的對應物品,以便測試
- 手機的primary gmail帳號要設成測試gmail帳號,不能用開發者的gmail帳號!
- APK必須發佈Alpha或Beta才能測試,利用所附的URL成為測試人員,然後下載APP.
- "錯誤!此項目目前無法購買"<----退出計畫,後重新成為測試人員!!
- 所欲購買項目必須啟動(in Active)
- "錯誤!請先入登入GOOGLE帳戶"<---加入Alpha/Beta測試計畫
- 測試帳號須登登錄信用卡資訊才能完成測試購買
//Does the user have the premium upgrade?
boolean mIsPremium = false;
//Does the user have an active subscription to the infinite gas plan?
boolean mSubscribedToInfiniteGas = false;
//SKUs for 產品:the premium upgrade(non-consumable)and gas(consumable)
static final String SKU_PREMIUM = "premium";
static final String SKU_GAS = "gas";
//SKU for our 訂閱subscription (infinite gas)
static final String SKU_INFINITE_GAS = "infinite_gas";
//(arbitrary) request code for the purchase flow
static final int RC_REQUEST = 10001;
//The helper object
IabHelper mHelper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//load game data
loadData();
//建議不要直接用一個字串來設定,這樣比較容易被破解!
String base64EncodedPublicKey ="....";
//產生helper物件,傳入context和金鑰
mHelper = new IabHelper(this, base64EncodedPublicKey);
//設定debug logging(for a production app, set it to false)
mHelper.enableDebugLogging(true);
// Start setup. This is asynchronous and the specified listener
// will be called once setup completes.
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
//有問題發生!
complain("Problem in in-app billing:"+result);
return;
}
// 起始成功,接著查詢此裝置已經擁有的物品
Log.d(TAG, "Setup successful.Querying inventory.");
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
//當我們查詢購買物品和訂閱資訊時,系統會呼叫此Callback
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new
IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
/*
*Check items we own.Notice that for each purchase,we check
*the developer payload to see if it's correct! See
*verifyDeveloperPayload().
*/
// 檢查是否有升級成premium?
Purchase premiumPurchase=inventory.getPurchase(SKU_PREMIUM);
mIsPremium = (premiumPurchase != null &&
verifyDeveloperPayload(premiumPurchase));
Log.d(TAG,"User is"+(mIsPremium ?"PREMIUM":"NOT PREMIUM"));
// 有訂閱無限汽油嗎?infinite gas subscription?
Purchase infiniteGasPurchase=
inventory.getPurchase(SKU_INFINITE_GAS);
mSubscribedToInfiniteGas =(infiniteGasPurchase != null &&
verifyDeveloperPayload(infiniteGasPurchase));
Log.d(TAG, "User " + (mSubscribedToInfiniteGas ? "HAS":
"DOES NOT HAVE")+ " infinite gas subscription.");
if (mSubscribedToInfiniteGas) mTank = TANK_MAX;
// 檢查是否有買汽油gas -- 如果有買,則立刻加入油箱。
Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
if(gasPurchase!=null&&verifyDeveloperPayload(gasPurchase)){
Log.d(TAG, "We have gas. Consuming it.");
// 將汽油用掉
mHelper.consumeAsync(inventory.getPurchase(SKU_GAS), mConsumeFinishedListener);
return;
}
updateUi();
setWaitScreen(false);
Log.d(TAG, "Initial inventory query finished.");
}
};
//買汽油按"Buy Gas"按鈕
public void onBuyGasButtonClicked(View arg0) {
Log.d(TAG, "Buy gas button clicked.");
if (mSubscribedToInfiniteGas) {
complain("No need!You're subscribed to infinite gas.");
return;
}
if (mTank >= TANK_MAX) {
complain("Your tank is full. Drive around a bit!");
return;
}
// launch the gas purchase UI flow.
// notified of completion via mPurchaseFinishedListener
setWaitScreen(true);
Log.d(TAG, "Launching purchase flow for gas.");
/*TODO:for security,generate your payload here for verification
*verifyDeveloperPayload() for more info.We use
*an empty string for example */
String payload = "";
mHelper.launchPurchaseFlow(this, SKU_GAS, RC_REQUEST,
mPurchaseFinishedListener, payload);
}
//按"Upgrade to Premium"按鈕
public void onUpgradeAppButtonClicked(View arg0) {
Log.d(TAG, "launching purchase flow for upgrade.");
setWaitScreen(true);
/*TODO:for security,generate your payload here for verification*/
String payload = "";
mHelper.launchPurchaseFlow(this, SKU_PREMIUM, RC_REQUEST,
mPurchaseFinishedListener, payload);
}
//訂閱infinite gas
public void onInfiniteGasButtonClicked(View arg0) {
if (!mHelper.subscriptionsSupported()) {
complain("Subscriptions not supported on your device yet!");
return;
}
String payload = "";
setWaitScreen(true);
Log.d(TAG, "Launching purchase for infinite gas subscription.");
mHelper.launchPurchaseFlow(this,
SKU_INFINITE_GAS, IabHelper.ITEM_TYPE_SUBS,
RC_REQUEST, mPurchaseFinishedListener, payload);
}
//當購買程序完成時,呼叫此Callback
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new
IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result,Purchase purchase){
Log.d(TAG,"Purchase ok:"+result+",purchase:"+purchase);
if (result.isFailure()) {
complain("Error purchasing: " + result);
setWaitScreen(false);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing.Authenticity failed.");
setWaitScreen(false);
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_GAS)) {
// bought 1/4 tank of gas. So consume it.
Log.d(TAG, "Starting gas consumption.");
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}
else if (purchase.getSku().equals(SKU_PREMIUM)) {
// bought the premium upgrade!
Log.d(TAG,"Purchase is premium upgrade.");
alert("Thank you for upgrading to premium!");
mIsPremium = true;
updateUi();
setWaitScreen(false);
}
else if (purchase.getSku().equals(SKU_INFINITE_GAS)) {
// bought the infinite gas subscription
Log.d(TAG, "Infinite gas subscription purchased.");
alert("Thank you for subscribing to infinite gas!");
mSubscribedToInfiniteGas = true;
mTank = TANK_MAX;
updateUi();
setWaitScreen(false);
}
}
};
//當物品完成使用時,呼叫此callback
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new
IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase,IabResult result){
Log.d(TAG,"Consumption ok.Purchase:"+purchase+",result:"+result);
//This is "gas" sku because it's the only one we consume,
//so don't check which sku was consumed.If have more than one
//sku, you probably should check...
if (result.isSuccess()) {
//successfully consumed,so apply effects of the item in
//game world's,which means filling the gas tank a bit
Log.d(TAG, "Consumption successful. Provisioning.");
mTank = mTank == TANK_MAX ? TANK_MAX : mTank + 1;
saveData();
alert("It's now"+String.valueOf(mTank)+"/4 full!");
}
else {
complain("Error while consuming: " + result);
}
updateUi();
setWaitScreen(false);
Log.d(TAG, "End consumption flow.");
}
};
// 記得要在這裡釋放helper物件!
@Override
public void onDestroy() {
super.onDestroy();
// very important:
Log.d(TAG, "Destroying helper.");
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
執行截圖:



沒有留言:
張貼留言