Restoring Purchases with the In-App Billing Module for Appcelerator and Android

Restoring Purchases with the In-App Billing Module for Appcelerator and Android

Update 8/19/15 – I’ve updated the module to fix an issue with queryInventory(). If the user had more than 20 purchases, inventory came back empty OR Google returned responseCode 5 (Developer Error). Until the changes are rolled into the In-App Billing module on Github (if they even are) – Here is a download link to the fix: ti.inappbilling-android-3.0.2

Google announced that support for Version 2 of their in-app purchasing API would soon end and any apps using it after January 2015 would no longer be able to make in-app purchases – Time to upgrade to V3! Luckily, the In-App Billing Module that is available for Appcelerator has recently updated and supports V3 of Google’s In-App Billing API. Anybody who used older versions of this module will be happy to know that as of version 3.0, it takes MUCH LESS code to make purchases and restore purchases. The GitHub page for the module has a great example of working with consumables, subscriptions and managed products – make sure to check it out after reading this post… or now if we bore you.

One thing that seemed to be lacking in the example and documentation was how to restore purchases. Maybe lacking isn’t the right word, but it just wasn’t very clear. Here is where this post comes in – How to restore purchases previously made in your application:

var restore = function(arg)
{
   InAppBilling.queryInventory();
   InAppBilling.addEventListener('queryinventorycomplete', function (e)
   {
        var inventory = e.inventory;
        var purchase;
        var rows = db.execute('SELECT * FROM tablename');
        var dataArray = [];
        while (rows.isValidRow())
        {
           dataArray.push(rows.fieldByName('store_id'));
           rows.next();    
        };
     
        for (var i = 0; i <= dataArray.length; i++)
        {
             if (inventory.hasPurchase(dataArray[i])) 
             {
                purchase = inventory.getPurchase(dataArray[i]);
                    if (purchase.purchaseState == 0)
                    {
                       //Do your database updating here if you store your items in a DB. Example:
                       db.execute('UPDATE tablename SET owned="1" WHERE store_id="'+purchase.productId+'"');
                    }
             }
        }
   });
};

Let’s break this down:

InAppBilling.queryInventory();

This method is what asks the Play Store, “Hey… Listen!”, just kidding, this method asks the Play Store to return an ‘Inventory Object’. The cool thing about this is, you can get details for a product ‘on the fly’. If you want to update your pricing inside the Play Store, you can have the Inventory Object update your pricing inside your app (if you display it anywhere else besides the purchasing window, which this application does). No more ‘hard coding’ pricing inside your app, but this isn’t why you’re here… Moving on!

InAppBilling.addEventListener('queryinventorycomplete', function (e)
   {
       //More Code Explanation Coming... 
   });

After calling our Inventory query, we have to listen for the response – That is what this does. If you don’t add your event listener, queryInventory is useless. Listen for  ‘queryinventorycomplete’ and then give it a callback function. Here, ‘e’ will be our response.

var inventory = e.inventory;
var purchase;
var rows = db.execute('SELECT * FROM tablename');

Just create an inventory variable to hold the actual inventory items from the response. The purchase variable is used to ‘get’ our purchase info… More on this later. Next, we create a variable and grab our rows from our database table. In this app, our table has product names, product Ids (store_id), an owned boolean and an ID. We only care about the product Id and the owned column at this point.

var dataArray = [];
        while (rows.isValidRow())
        {
           dataArray.push(rows.fieldByName('store_id'));
           rows.next();    
        };

Next, create an array to hold all of the product Ids that need checked for purchase history. That’s what dataArray was tasked to do. Loop through your database with this ‘while’ loop, ‘push’ the store_id field into the array and then move on to the next row. Pretty straight forward.

for (var i = 0; i <= dataArray.length; i++)
        {
             if (inventory.hasPurchase(dataArray[i])) 
             {
                purchase = inventory.getPurchase(dataArray[i]);
                    if (purchase.purchaseState == 0)
                    {
                       //Do your database updating here if you store your items in a DB. Example:
                       db.execute('UPDATE tablename SET owned="1" WHERE store_id="'+purchase.productId+'"');
                    }
             }
        }

Here is where the magic happens – Loop through each of our Product Ids and see if they have been purchased (and are still valid, e.g. not refunded). First, we have to check to see if the product was actually purchased at some point, that is what hasPurchase() does. If there isn’t a purchase history, skip it. If there IS a purchase history, we need to ‘get’ the purchase. getPurchase() will actually return quite a bit of information, like the type (product or subscription), orderID, packageName, productID, purchaseTime, purchaseState (important here) – where zero is purchased, one is canceled and 2 is refunded – developerPayload and token.

You probably get the idea here by now – get the purchased State and if it equals zero (purchased) do whatever you need to get that product restored in your app. We simply switched our boolean to TRUE and that gave our user their purchase. Pretty easy, just a few more steps than simply querying the inventory.

Leave a Reply