2016年9月15日 星期四

Android 使用預設 product key 測試 App 內購買(In-app Billing)


Google 說明文件寫可以使用 android.test.purchased、android.test.canceled、android.test.refunded、android.test.item_unavailable 當 product id 測試,
輸入 android.test 時,
android studio 還會確定有這個物件,
但是再加上 . 後就沒有顯示要使用的變數,
原來這幾個是要當作字串傳給google。

使用這個方法不用先進行app 發布到 alpha 或 bata,
如果要測試在 develop console 中加入的商品,
就要填完所有必填資料,
按「發布應用程式」按鈕,將app 發布到 alpha 或 bata。
像左圖沒按發布應用程式,
就算填了服務和 API 內的公開金鑰,
也只會收到空的商品的訊息,
不會出現錯誤。


使用 google example 提供的 IAB 工具庫



String REQUEST_CODE_IAB = "上圖中 Google Play Developer Console 的公開金鑰"

// 因為程式碼從正式app 改過來,刪掉專案使用的部份,可能有部份語法錯誤。
private static String mCurrencyPrefix = "";
private IabHelper mIabHelper = null;
private Inventory mInventory = null;private Map<String, String> mSkuPriceMap = new HashMap<>();
 

mIabHelper = new IabHelper(MainActivity.this, IAB_PUBLIC_KEY);
 

mIabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
    @Override 
    public void onIabSetupFinished(IabResult result) {
        if ( !result.isSuccess()) {
            Toast.makeText(getContext(), result.toString() , Toast.LENGTH_LONG).show();

        } else {
        final List<String> skuList = new ArrayList<>();
        skuList.add("yourProductId"); 
            try {
        mIabHelper.queryInventoryAsync(true, skuList, null, new IabHelper.QueryInventoryFinishedListener(){

        @Override        public void onQueryInventoryFinished(IabResult result, Inventory inv) {
            mInventory = inv;
            for (String sku : skuList) {
                if (inv.hasDetails(sku)) {
                    SkuDetails details = inv.getSkuDetails(sku);

                    mSkuPriceMap.put(sku, details.getPrice());
                    if (mCurrencyPrefix.isEmpty()) {
                        String currencyCode = details.getPriceCurrencyCode();

                        mCurrencyPrefix = Currency.getInstance(currencyCode).getSymbol();
// 到這裡 detail.getPrice() = $100.00 , mCurrencyPrefix = NT$
// 以下 將 mCurrencyPrefix 改成 NT
                         char lastChar = mCurrencyPrefix.charAt(mCurrencyPrefix.length() -1);

                        if( lastChar == details.getPrice().charAt(0)
                                && ( lastChar < '0' || lastChar > '9')) {
                            mCurrencyPrefix = mCurrencyPrefix.substring(0, mCurrencyPrefix.length() - 1);

                        }
                    }
                }else {
                    // 沒有資料
                    mSkuPriceMap.put(sku, "???");

                }
            }
        }
    });} catch (IabHelper.IabAsyncInProgressException e) {
    e.printStackTrace();

}        }
    }
});
購買後的 listener
IabHelper.OnIabPurchaseFinishedListener listener = new IabHelper.OnIabPurchaseFinishedListener() {

         @Override

         public void onIabPurchaseFinished(IabResult result, Purchase info) { 
             if(result.isFailure()) {
                Toast.makeText(getContext(), result.toString(), Toast.LENGTH_LONG).show();

             } else if(result.isSuccess() ) { 
                 // 付款完成後
             } 
         }
); 
 
購買測試
 
if(! mInventory.hasPurchase(sku)) {
            try {
                mIabHelper.launchPurchaseFlow(MainActivity.this, "android.test.purchased",

                        REQUEST_CODE_IAB, listener
 , "test key");            } catch (IabHelper.IabAsyncInProgressException e) {
                e.printStackTrace();

            }
        }
正式購買
if(! mInventory.hasPurchase(sku)) {
            try {
                mIabHelper.launchPurchaseFlow(MainActivity.this, sku,

                        REQUEST_CODE_IAB, listener, "test key");

            } catch (IabHelper.IabAsyncInProgressException e) {
                e.printStackTrace();            }
        }
 


google 在範例程式的MainActivity.java 有說明實做"test key"方式
以下引用內容:
TODO: verify that the developer payload of the purchase is correct. It will be
the same one that you sent when initiating the purchase.

WARNING: Locally generating a random string when starting a purchase and
verifying it here might seem like a good approach, but this will fail in the
case where the user purchases an item on one device and then uses your app on
a different device, because on the other device you will not have access to the
random string you originally generated.

So a good developer payload has these characteristics:

1. If two different users purchase an item, the payload is different between them,
   so that one user's purchase can't be replayed to another user.

2. The payload must be such that you can verify it even when the app wasn't the
   one who initiated the purchase flow (so that items purchased by the user on
   one device work on other devices owned by the user).

Using your own server to store and verify developer payloads across app
installations is recommended.

沒有留言:

張貼留言