Now when your app is rocking the Play Store, has 1m+ downloads and a big community of fans, it’s time to think about monetization. I bet, the first thing you stumble upon while searching for “android in-app billing” is from the official Android documentation. this article And you should read it. Seriously, without a deep understanding of APIs provided from the SDK, without knowledge of the base data structures, method signatures and terms used in the documentation, adding in-app purchases to your app is going to be painful and will take a lot of time and effort. Let’s assume that you have read the article and know the difference between the managed products and the subscriptions. You’re aware that you can’t cancel a subscription from within the app, only downgrade or upgrade it. You know what “consuming” means. What’s next? There are, basically, two alternatives: either you implement billing yourself or you use some library for it. Implementing billing yourself There is a great on Android Developer portal about it. Just follow it. guide However, this approach has several disadvantages, such as: Once imported the code of becomes your responsibility. If it changes due to an API change or a bug fix, then you need to update your project. As now they are inseparable. Trivial Drive doesn’t provide callbacks for purchase signature verification that is to be performed on a remote server. Trivial Drive recommended is not efficient: it establishes one connection to the billing service per , creates a new thread each asynchronous request, etc. Trivial Drive IabHelper You don’t need to be a genius to understand that code just smells, see and , for example. Trivial Drive MainActivity IabHelper Have you already changed your mind? Using a billing library There are to choose from. This tutorial uses , a well-documented and efficient in-app billing library with high test coverage. several libraries Checkout I’m going to show you how to implement common tasks using the library’s sample app. If you prefer digging in the code yourself here is a range of changes in that are used in this tutorial: . git .. 0d95bf5 54789c3 Let’s start! Step #0. Preparation First, we need to import the library into the app’s project. In Gradle it can be done with the following one-liner: compile 'org.solovyev.android:checkout:1.0.0' Let’s define a custom application class, , with a single object. As Android creates Application only once, we’re guaranteed to have only one instance of . It’s important as some operations performed by it shouldn’t be done more than once (for example, binding to the billing service). bb989bf CheckoutApplication Billing Billing If your app uses a DI framework class can be marked as a singleton. Billing . Here we introduce the main activity which shows a list of use cases available in the app. The code is straightforward: activity contains an enum ( ) that represents all use cases available in the app (empty initially), an adapter and a view holder to show each use case in the list ( + ). 3c57339 UseCase RecycleView LinearLayoutManager . Get hold of through , which is needed to access in the UI code_._ 6198659 CheckoutApplication Activity Billing Use case #1. Static responses Goal To test the static responses as described on . d.android.com Implementation . creates an instance of class via call. It is immediately started and then used in the Buy button’s callback. Note also that it is used in two other methods: and . The former is needed to free any resources that might be acquired by while the latter merely notifies about the purchase result. 3a8966b StaticActivity Checkout Checkout#forActivity Activity onDestroy onActivityResult Checkout Checkout initiates connection to the billing service. disconnects from it. These two methods should always be used in pair — every time a instance is started it should be stopped. Checkout#start Checkout#stop — Checkout Use case #1. Static responses . is aware now of what is happening under the hood of the library and logs everything on the screen into the console . 76c0ffb StaticActivity TextView Time to run the code… And it doesn’t work. Damn! It turned out that some static responses are broken. is not the bug you’re looking for, move along. This Use case #2. Ad banner Goal To show an ad banner. The banner should be removed if user purchases an ad-free version. Implementation This commit starts with declaration of which shows some text and an ad banner. As in the previous example, we need to write some boilerplate code to obtain an instance of and start loading. As it might take some time to load the inventory, the banner is hidden at the beginning (we don’t want to show it at all if user has already done the purchase). 6429f48 . BannerActivity Checkout Inventory Inventory loading consists of 3 steps: Preparing a request, for example: Inventory.Request.create().loadAllPurchases() Calling Checkout#loadInventory Waiting for the result in Inventory.Callback Use case #2. Ad banner Good to know that cancels all pending requests, including inventory loading. Thus, is never called after the enclosing activity is destroyed. Checkout#onStop Inventory.Callback The code of is straightforward: if billing is not supported do nothing (no banner is shown in this case); if ad-free option is not purchased — show the banner. BannerActivity.InventoryCallback Here we add a menu to the activity with a single “Remove ad banner” entry. By clicking it we start a purchase flow which ends in (or in if something goes wrong :P). just hides the banner in the callback method. 01c48ea . RequestListener#onSuccess RequestListener#onError BannerActivity.PurchaseListener Use case #3. List of SKUs Goal To show a list of SKUs fetched from Play Store. User can purchase/consume items in the list. Implementation The main activity in this example is . It shows a list of SKUs that are loaded with the help of method. 7963597 . SkusActivity Checkout#loadInventory Use case #3. List of SKUs In contrast to the use case #2, where only purchases are loaded, here we also want to load listings from the store. Unfortunately, Android’s billing API doesn’t allow to load all available at the moment items — a list of SKU identifiers is required by that handles such request. the API method prepares the identifiers list in method and uses it in right before is called. updates the adapter when the loading finishes. SkusActivity #getInAppSkus Inventory.Request#loadSkus Checkout#loadInventory InventoryCallback Next commit makes items in the list clickable. calls either or depending on the current state of the clicked item. At the end of the operation, the list is reloaded via call. e11a495 . Adapter#onClick SkusActivity#purchase SkusActivity#consume SkusActivity#reloadInventory Use case #4. Managing subscriptions Goal To show a list of subscriptions and provide user interface for managing them. Implementation . The main activity in this use case, namely , allows user to: 9aec6c4 SubscriptionsActivity Buy subscriptions Replace purchased subscriptions (upgrade/downgrade) Use case #4. Managing subscriptions As you might have noticed user can’t cancel a purchased subscription but can only convert it to some other subscription. The reason for that is simple — the billing API subscription cancellation. Until this is changed in the API the only one way of managing subscriptions in the app is by replacing purchased subscriptions. doesn’t allow As in the use case #3, we need some subscription information (title, for example) to be loaded from Play Store. defines a list of subscription identifiers used in this example. SubscriptionsActivity#SKUS The UI consists of 3 adapter-like views: # , representing SKUs available for purchase mAvailableSkus Spinner # which contains purchased subscriptions mPurchasedSkus RecyclerView # representing SKUs available for “replacement” mTargetSkus Spinner, All of the adapters are notified every time the inventory is reloaded in method. SubscriptionsActivity#reloadInventory When user presses “Buy” button we start a purchase flow in the same way as for any other in-app (see previous uses cases for details). After the purchase is gone through user can select the purchased subscription and change it to another subscription selected in the spinner to the left of “Change” button. This triggers from the billing API at the end of which the new subscription replaces the old one in the “purchased subscriptions” section. getBuyIntentToReplaceSkus *** That’s it for now. If you have any questions or suggestions (like use cases you want to be covered) don’t hesitate to write them in the comments. Found a bug in the library? Feel free to submit a bug report on . github