Configuring Cordova In App Purchases on iOS and Android

This post goes over the differences between setting up consumable and non-consumable in app purchases on iOS and Android and restoring non-consumable purchases from different devices.

Non-Consumables

Non-Consumables are products that the user can purchase only once. For example, if you have a game with multiple levels, you can configure every level to be a paid purchase and define a product for each level (such as com.yourcompany.level1, com.yourcompany.level2, etc). When users purchase one of these products, they should own it forever (or for as long as there are humans and iPhones) which means that you have to provide a way to restore this product if the app is opened from another device using the same iTunes/google account.

When you offer non-consumable products, you must provide functionality to restore these purchases so the user will not have to pay for them again if they re-download the app or use if from a different device.

To restore non-consumable purchases, use inAppPurchase.restorePurchases():

inAppPurchase.restorePurchases().then((purchases)=>{purchases.forEach(purchase=>console.log(purchase.productId+' should be restored'));// unlock the relevant feature based on this product id}).catch(err=>console.log(err));

Iterate over the purchases array and unlock all the features for the products that were previously purchased.

Consumables

Consumables are products that the user can purchase multiple times such as credits or coins. For example, in a slot machine app, you may charge the user 1 credit for each game and let them purchase a package of 20 credits by offering the product com.yourcompany.20_credits.

When you are adding a new consumable product on iOS, one of the options will be to add a consumable in app purchase:

On Android, there is no distinction between consumable and non-consumable products. They both fall under the "Managed Product" Category.

To indicate that this product is consumed, you need to call the inAppPurchase.consume(productId) function. It's important to remember to consume the product, otherwise you will get an error the next time you will try to purchase it.

To purchase a consumable product:

constproductId='com.yourcompany.20_credits';letvalidationData={};inAppPurchase.buy(productId).then((res)=>{validationData=res;// give the user credits for their purchasereturninAppPurchase.consume(productId);// <- consumable products must be consumed}).then(()=>{validateOnYourBackend({receipt:validationData.receipt,signature:validationData.signature,});}).catch(err=>console.log(err))

Consumable purchases cannot be restored like non-consumable purchases. You should avoid putting a "Restore Purchases" button if your app only offers consumable products. Instead ask the user to authenticate and sync their purchased consumable products.

When a user purchases credits, you will need to keep track how many credits the user owns and the usage of credits. You can do that by uniquely identifying the user (by his credentials or any other unique identifier) and sending the information about purchases and games played to your server to sync this data between devices. You can also store this data locally using any of the available storage solutions (local storage, sqlite, etc). If your app doesn't use a backend, there is a solution to persist the data on the device even if the app is uninstalled.

Follow me for updates on similar new posts I write or tweet about this post.