In App Billing 學習 I

要學習Google的In App Billing可以從他的範例來學,也可以直接套用,即方便又不容易出錯。要學習之前我們先做一下基本的準備。在Android developer中,提供了一個車子買油的小範例 TrivialDrive

TrivialDrive 這個範例就在 android的sdk 下的/extras/google/play_billing/sample。我們方便些,把sample下的src的裡的java都複製到我們的project的src下吧。有如下幾個檔名:

IabHelper.java
IabResult.java
IabException.java
Inventory.java
Purchase.java
Security.java
SkuDetails.java
Base64.java
Base64DecoderException.java



第一步:
先在 AndroidManifest.xml 加入
<uses-permission android:name="com.android.vending.BILLING" />

第二步 : 
在src底下創建一個新的package, 名為com.android.vending.billing,再把 IInAppBillingService.aidl(也是在android的sdk 下的/extras/google/play_billing/ 可找到) 複製到 src目錄下的package->com.android.vending.billing底下

第三步:
建立商品。進入自已的market->應用程式內產品
 點擊新增產品
產品ID只能有小寫(a-z)、數字(0-9)、底線(_)和小數點(.)。
不管是不是納入管理產品,其實google都有管理,所以就選納入管理吧。訂閱是指一個固定周期的付費,像是雜誌每個月的付費之類。


第四步:
找出public key。進入自已的market


複製public key後,就存放在程式裡吧。如下在 onCreate 中

@Override
public void onCreate(Bundle savedInstanceState) {

    String base64EncodedPublicKey;  //market 中複製來的public key 
    mHelper = new IabHelper(this, base64EncodedPublicKey); 
    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
    public void onIabSetupFinished(IabResult result) {
        if (!result.isSuccess()) {
            // Oh noes, there was a problem.
            Log.d("inAppBilling", "Problem setting up In-app Billing: " + result);
        }else{
            mHelper.queryInventoryAsync(mGotInventoryListener);
        }
    }
});


記得在onDestroy裡加上

@Override
public void onDestroy() {
   super.onDestroy();
   if (mHelper != null) mHelper.dispose();
   mHelper = null;
}
 
到這裡為止,我們已經開始了In App Billing的
服務了。


我們先來研究一下 mHelper.startSetup 作了些什麼動作。進入IabHelper.java,在startSetup 方法中可以找到

response = mService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP);

response =mService.isBillingSupported(3, packageName, ITEM_TYPE_SUBS);

response=0, 代表ok!

developer上的圖的第一步(右圖),先檢查是否支援交易和SDK版本。當然startSetup還建立了連線和服務,這個不在話下。


第五步:
我們可以參考範例 TrivialDrive 的MainActivity.java。在onCreate()中建立物件IabHelper後。在onCreate()外,重寫了IabHelper的

IabHelper.QueryInventoryFinishedListener
IabHelper.OnIabPurchaseFinishedListener
IabHelper.OnConsumeFinishedListener

因為參考範例 TrivialDrive 有三種產品 
1、SKU_PREMIUM。2、SKU_INFINITE_GAS。3、SKU_GAS。

完整的Code如下

IabHelper.QueryInventoryFinishedListener

IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {

        public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
            Log.d(TAG, "Query inventory finished.");
            if (result.isFailure()) {
                return;
            }

            Log.d(TAG, "Query inventory was successful.");
            
       
            // Do we have the premium upgrade?
            Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);           //SKU_PREMIUM為內建產品的ID
            mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
            Log.d(TAG, "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
            
            // Do we have the infinite gas plan?
            Purchase infiniteGasPurchase = inventory.getPurchase(SKU_INFINITE_GAS);    //SKU_INFINITE_GAS為內建產品的ID
            mSubscribedToInfiniteGas = (infiniteGasPurchase != null && 
                    verifyDeveloperPayload(infiniteGasPurchase));
            Log.d(TAG, "User " + (mSubscribedToInfiniteGas ? "HAS" : "DOES NOT HAVE") 
                        + " infinite gas subscription.");
            if (mSubscribedToInfiniteGas) mTank = TANK_MAX;

            // Check for gas delivery -- if we own gas, we should fill up the tank immediately
            Purchase gasPurchase = inventory.getPurchase(SKU_GAS);                     //SKU_GAS為內建產品的ID
            if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)) {
                Log.d(TAG, "We have gas. Consuming it.");
                mHelper.consumeAsync(inventory.getPurchase(SKU_GAS), mConsumeFinishedListener);
                return;
            }

            updateUi();
            Log.d(TAG, "Initial inventory query finished; enabling main UI.");
        }
    };

IabHelper.OnIabPurchaseFinishedListener 如下


IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
        public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
            Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
            if (result.isFailure()) {
                return;
            }

            Log.d(TAG, "Purchase successful.");

            if (purchase.getSku().equals(SKU_GAS)) {                        //SKU_GAS為內建產品的ID              

                // bought 1/4 tank of gas. So consume it.
                Log.d(TAG, "Purchase is gas. Starting gas consumption.");
                mHelper.consumeAsync(purchase, mConsumeFinishedListener);
            }
            else if (purchase.getSku().equals(SKU_PREMIUM)) {              //SKU_INFINITE_GAS為內建產的ID


                // bought the premium upgrade!
                Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
                alert("Thank you for upgrading to premium!");
                mIsPremium = true;
                updateUi();
               
            }
            else if (purchase.getSku().equals(SKU_INFINITE_GAS)) {         //SKU_INFINITE_GAS為內建產品的ID     

           // 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();
               
            }
        }
    };



IabHelper.OnConsumeFinishedListener 如下

 IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
        public void onConsumeFinished(Purchase purchase, IabResult result) {
            Log.d(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result);

            // We know this is the "gas" sku because it's the only one we consume,
            // so we don't check which sku was consumed. If you have more than one
            // sku, you probably should check...
            if (result.isSuccess()) {
                // successfully consumed, so we apply the effects of the item in our
                // game world's logic, which in our case means filling the gas tank a bit
                Log.d(TAG, "Consumption successful. Provisioning.");
                mTank = mTank == TANK_MAX ? TANK_MAX : mTank + 1;
                saveData();
                alert("You filled 1/4 tank. Your tank is now " + String.valueOf(mTank) + "/4 full!");
            }
            else {
                complain("Error while consuming: " + result);
            }
            updateUi();
            Log.d(TAG, "End consumption flow.");
        }
    };





到這裡算是把In App Billing 都建好了,如果想要進行購買只要

mHelper.launchPurchaseFlow(this, SKU_GAS, RC_REQUEST, mPurchaseFinishedListener, payload);

寫入某個按鈕中即可開始交易。SKU_GAS 也可以改成 SKU_PREMIUM 或SKU_INFINITE_GAS。


我們來追蹤一下 launchPurchaseFlow 在IabHelper中的流程。我們再查閱一次流程圖


在IabHelper中我們可以找到launchPurchanseFlow的程式,裡面包含了getBuyIntent,等待google回應之後,再執行startIntentSenderForResult,如下
 
 try {
            logDebug("Constructing buy intent for " + sku + ", item type: " + itemType);
            Bundle buyIntentBundle = mService.getBuyIntent(3, mContext.getPackageName(), sku, itemType, extraData);
            int response = getResponseCodeFromBundle(buyIntentBundle);
            if (response != BILLING_RESPONSE_RESULT_OK) {
                logError("Unable to buy item, Error response: " + getResponseDesc(response));

                result = new IabResult(response, "Unable to buy item");
                if (listener != null) listener.onIabPurchaseFinished(result, null);
                return;
            }

            PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT);
            logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode);
            mRequestCode = requestCode;
            mPurchaseListener = listener;
            mPurchasingItemType = itemType;
            act.startIntentSenderForResult(pendingIntent.getIntentSender(),
                                           requestCode, new Intent(),
                                           Integer.valueOf(0), Integer.valueOf(0),
                                           Integer.valueOf(0));
        }


到此,大概可以了解整個使用的過程,下一篇我們追蹤一下範例中
IabHelper.QueryInventoryFinishedListener
IabHelper.OnIabPurchaseFinishedListener
IabHelper.OnConsumeFinishedListener
這三個Listener的流程。就可以自已改寫了。
 
 

留言

這個網誌中的熱門文章

python 找圖自動點擊

Python pyserial 抓取系統內的 COM PORT

VBA EXCEL 工作表變化 馬上執行 的作法 Worksheet_Change