Wednesday, 18 April 2012

Deploying on multiple markets with in-app purchases

Last year, Google introduced in-app purchases for apps for the Android Market. This provided developers with an alternative model for generating income from apps. Rather than having a two versions of an app (limited free and paid-for premium), developers could now release a single app, with premium content being unlocked via in-app purchases.

More recently, Amazon have also announced a similar in-app purchase system, with promising initial results.

The downside with this in-app purchase model comes when developers have products available on several different app markets. Google's in-app purchase system only works through their own Android Market. So, what to do if you want to leverage in-app purchases, but also want to make your app available on a number of markets?

Well, there are no doubt various possible solutions, but this is what I have come up with. The strategy is essentially:

1. Create a "basic" (free) version of the app - this is the version that is available on markets which don't support in-app purchases.
2. For each market with in-app purchases that you want to support, there will be a separate version of the app. This is less work than it sounds if you simply take the basic version and extend it with the extra features. Then use a common interface to manage the different in-app billing systems.

Here are two suggested interfaces to use for handling in-app billing: public interface BillingHelper { /* initialize the billing system */ public abstract void init(Activity activity, BillingListener listener); /* call when activity.onStart() */ public abstract void start(); /* call when activity.onResume() */ public abstract void resume(); /* call when activity.onDestroy() */ public abstract void destroy(); /* determine whether billing is available */ public abstract boolean isBillingAvailable(); /* determine if a product ID is currently owned */ public abstract boolean isOwned(String itemId); /* request the purchase of a product */ public abstract void purchase(String itemId, String payload); }
public interface BillingListener { public void doUpdate(); }
Then, these interfaces are implemented for each market which supports in-app billing. The key to making life as simple as possible here, is that the different versions of the app can use entirely the same code except for switching between which BillingHelper implementation they choose, and the native billing code for that market:

A typical implementation would work like this... The basic version of the app can query the BillingHelper interface to determine whether billing is available (via the isBillingAvailable method), and only make enable the option the purchase upgrades if this is the case. When the user is ready to purchase an upgrade, the purchase method is called, and the payment and billing are handled by the appropriate BillingHelper implementation and the billing SDK.

The BillingListener interface is used to detect when a purchase event has occured, so the app can take the required action, such as downloading/unlocking the paid-for levels.

With this approach, although it remains necessary to maintain different versions of the app for each market you want to target, in practise nearly all the code is maintained in the basic version of the app. The additional versions for the specific markets are constructed via build scripts, in my case using ant.

Well, that's the strategy I plan to use to build different versions of my apps for a variety of app stores. If you have an alternative approach or a suggestion for improvement, do let me know!

Update 1:
On closer inspection of the Amazon developer payments system, it seems they are totally not set up to deal efficiently with non-US developers! Apparently it is required to obtain a US taxpayer identification, then fill in some US tax forms, and at the end of all that, they make payments by sending US$ cheques out in the mail. Seriously, US$ cheques???

This policy makes Amazon currently unusable for selling products in my view. They should definately take a leaf out of Google's book when it comes to payments. As an international company I would have expected better from Amazon. Let's hope they sort this problem out soon!

Update 2:
Amazon have recently much improved their services for non-US developers. The Amazon app store is now available in multiple counties, and developers in a lot more countries now have the opportunity to get paid in their home currency via bank transfer. Better late than never!