Restore purchases in In-app Billing (IAB Version 3) android

Bhavesh Hirpara picture Bhavesh Hirpara · Dec 15, 2012 · Viewed 11.7k times · Source

Google has upgraded to IAB3(In App Billing version 3). First what a issue in example code.. super.onDestroy() is missed.

I implemented v3 with the help of http://developer.android.com/google/play/billing/billing_integrate.html

It is tested on phone, does not work in emulator.It stuck in emulator.

My issue is, I did not see the API for restoring transactions. How can I restore purchases with IAB3? Is it mService.getPurchases(apiVersion, packageName, type, continuationToken). Has anyone tested this?? Does this returns purchased items from locally stored items or does it restore purchased items? Uninstalling application does not have continuationToken. Should it be null?

And What about when the purchase state changes??

Please help!

Thanks in advance.

EDIT :

Google has updated the In app billing library and solved the super.onDestroy() issue. They have also added some additional features.

Answer

Deepanshu picture Deepanshu · Dec 21, 2012

To make item consumable you have to sent a consume request and you have to do that in separate thread.

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 1111) {
        int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
        String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
        String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
        Logger.printMessage(TAG, "on activity result reponse"
                + responseCode, Logger.DEBUG);
        if (resultCode == RESULT_OK && responseCode == 0) {
            try {
                JSONObject jo = new JSONObject(purchaseData);
                String sku = jo.getString("productId");
                String title = jo.getString("title");
                addChipsToBalance(sku);
                final String token = jo.getString("purchaseToken");
                Toast.makeText(BuyChipsActivity.this,
                        "You have bought " + title + ". Enjoy the game!",
                        Toast.LENGTH_SHORT).show();

                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        Logger.printMessage(TAG, "inside run", Logger.DEBUG);
                        try {
                            int response = mService.consumePurchase(3,
                                    getPackageName(), token);
                            Logger.printMessage(TAG, "inside run response"
                                    + response, Logger.DEBUG);
                        } catch (RemoteException e) {
                            // TODO Auto-generated catch block
                            Logger.printMessage(TAG, "exception here 1",
                                    Logger.DEBUG);
                            e.printStackTrace();
                        }
                    }
                }).start();
                // alert("You have bought the " + sku +
                // ". Excellent choice,  adventurer!");
            } catch (JSONException e) {
                // alert("Failed to parse purchase data.");
                e.printStackTrace();
            }
        }
    }

But sometimes consume request is not completed on google end so you may want to query the purchased item list and consume it with the purchase token. I did like this

   private void showPreviousPurchases() {
    Logger.printMessage(TAG, "previous purchases", Logger.DEBUG);
    if (mService == null) {
        Toast.makeText(this, "Something Went Wrong. Try later",
                Toast.LENGTH_LONG).show();
        return;
    }
    Bundle ownedItems = null;
    ;
    try {
        ownedItems = mService.getPurchases(3, getPackageName(), "inapp",
                null);
    } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    if (ownedItems == null) {
        Logger.printMessage(TAG, "criical error ", Logger.DEBUG);
        return;
    }
    int response = ownedItems.getInt("RESPONSE_CODE");
    if (response == 0) {
        ArrayList<String> ownedSkus = ownedItems
                .getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
        ArrayList<String> purchaseDataList = ownedItems
                .getStringArrayList("INAPP_PURCHASE_DATA_LIST");
    /*  ArrayList<String> signatureList = ownedItems
                .getStringArrayList("INAPP_DATA_SIGNATURE");
        String continuationToken = ownedItems
                .getString("INAPP_CONTINUATION_TOKEN");*/

        for (int i = 0; i < purchaseDataList.size(); ++i) {
            String purchaseData = purchaseDataList.get(i);
            Logger.printMessage(TAG, "json  = " + purchaseData,
                    Logger.DEBUG);
            // String signature = signatureList.get(i);
            String sku = ownedSkus.get(i);

            addChipsAndMakeItConsumable(purchaseData);
            // do something with this purchase information
            // e.g. display the updated list of products owned by user
        }

        // if continuationToken != null, call getPurchases again
        // and pass in the token to retrieve more items
    }

}

private void addChipsAndMakeItConsumable(String purchaseData) {

    try {
        JSONObject jo = new JSONObject(purchaseData);
        String sku = jo.getString("productId");
        // String title = jo.getString("title");
        addChipsToBalance(sku);
        final String token = jo.getString("purchaseToken");
        Logger.printMessage(TAG, "id  = " + sku, Logger.DEBUG);

        Logger.printMessage(TAG, "inside run", Logger.DEBUG);
        try {
            int response = mService.consumePurchase(3, getPackageName(),
                    token);
            Logger.printMessage(TAG, "inside run response" + response,
                    Logger.DEBUG);
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            Logger.printMessage(TAG, "exception here 1", Logger.DEBUG);
            e.printStackTrace();
        }

        // alert("You have bought the " + sku +
        // ". Excellent choice,  adventurer!");
    } catch (JSONException e) {
        // alert("Failed to parse purchase data.");
        e.printStackTrace();
    }
}