2017年7月28日

Android: In-app-billing 付費機制Google範例

Preparing Your In-app Billing Application
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;
    }

執行截圖:





沒有留言: