Implementing in-app billing and subscriptions on Android

Niklas Baudy
3 min readSep 8, 2018

--

When implementing in-app billing or subscriptions back in the days you had to use the AIDL file. You had to copy it into your project and then use the raw bare bone API. Luckily, the documentation was decent. The API is still slightly cumbersome and even Google realized that - they introduced their Google Play Billing library.

While the new API is much better, I am personally not that comfortable with it. Too many callbacks, too many Builders and overall a bit verbose.

Personally, I prefer working with RxJava and it can be applied quite nicely to billing. If you think about it from a developers perspective there are a few things you want to do:

  • Check whether in-app billing or subscription is supported
  • Query in-app billing or subscription meta information (e.g. prices)
  • Purchase in-app billing or subscription
  • Query for in-app billings or subscriptions that you have bought
  • Consume an in-app purchase so they can be rebought

If you model those requirements into an interface you might get something like this:

public interface RxBilling {
Completable isBillingForInAppSupported();

Completable isBillingForSubscriptionsSupported();
Observable<InventoryInApp> queryInAppPurchases(String... skuIds);

Observable<InventorySubscription> querySubscriptions(
String... skuIds);

Single<PurchaseResponse> purchase(Inventory inventory,
String developerPayload);

Observable<PurchasedInApp> getPurchasedInApps();

Observable<PurchasedSubscription> getPurchasedSubscriptions();

Single<Integer> consumePurchase(PurchasedInApp purchasedInApp);

@interface BillingResponse {
int OK = 0;
int USER_CANCELED = 1;
int SERVICE_UNAVAILABLE = 2;
int BILLING_UNAVAILABLE = 3;
int ITEM_UNAVAILABLE = 4;
int DEVELOPER_ERROR = 5;
int ERROR = 6;
int ITEM_ALREADY_OWNED = 7;
int ITEM_NOT_OWNED = 8;
}
}

This is my approach that I came up with when developing RxBilling.

Underlying implementation

Now was the time for choosing which implementation (AIDL or in
Google Play Billing) I should use.

I went with the old school AIDL file since:

  • I still had some old half-baked implementation that I could reuse
  • I didn’t want an extra dependency (Google Play Billing) where it wasn’t needed
  • I’m okay with the burden of the AIDL API in a library which encapsulates it

Consuming

It’s quite easy. Simply add the dependency:

implementation 'com.vanniktech:rxbilling:0.1.0'

And hook it up in your activity:

class YourActivity extends Activity implements NaviComponent {
private RxBilling rxBilling;

@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate();
rxBilling = new RxBillingV3(this);
}

@Override public void onDestroy() {
super.onDestroy();
rxBilling.destroy();
}
}

That’s all you need to do. The destroy() method will kill the internal reference of the Activity you provided — so that there’s no memory leak.

Everything else is up to you and your business logic.

Not all flowers are roses

Currently, the Activity needs to be a NaviComponent. This is due to the fact that there's no 'Lifecycle' callback for onActivityResult. Though, this could be improved in the future by using a headless Fragment instead.

Conclusion

I needed in-app billing support in one of my apps. I chose to go down this way and offer it as an SDK. I can quite easily reuse the library in the future and I hope it brings some values to other developers as well.

Let me know what you think.

--

--