Posted by Oscar Rodriguez, Developer Advocate
When designing and developing an app or game, at some point you may ask yourself if you want to monetize it.
If you choose to do so by selling products via Google Play, you will most likely have a store screen that shows available items for sale, and use the Google Play Billing Library to display dialogs that allow your users to complete their purchase.
While there is a more detailed explanation in the documentation and in the Billing Library TrivialDrive samples, the general flow is as follows:
launchBillingFlow()
onPurchasesUpdated()
consumeAsync()
acknowledgePurchase()
If your app is still using the Google Play Billing AIDL API, it is also possible to perform the same task. Keep in mind that the AIDL API is now deprecated, so we strongly recommend you migrate to the Google Play Billing Library as soon as possible.
If you are using the AIDL API, the flow is very similar:
getBuyIntent()
getBuyIntentExtraParams()
startIntentSenderForResult()
Intent
onActivityResult()
getPurchases()
consumePurchase()
Nevertheless, just implementing the above mentioned flow is not enough to correctly handle all types of purchases. There are two main cases in which purchases will not be correctly handled by this flow.
The first case happens when the purchase flow is interrupted before it finishes. The app may have crashed, the user may have killed the app, or the user’s Internet connection may have been lost. In any case, it is possible for the app not to have delivered the item to the user even though Google Play has already processed the payment. In this case, the item is in limbo, because Google Play will not allow an item to be re-purchased until it is consumed, but the app or game won’t consume the item outside of the flow mentioned above.
The second case happens during alternative purchase flows, such as in-app promotions, the recently announced out-of-app subscription surfaces, promo codes for subscriptions, or other promotions in collaboration with Google. In these cases, a user gets an item directly on the Play Store app, while the target app or game may be paused, not running, or even not installed.
For these cases, the Google Play Billing Library and the Google Play Billing AIDL API offer a mechanism to detect purchases that are not acknowledged or consumed.
When using the Google Play Billing API, do the following:
onResume()
queryPurchases()
For the Google Play Billing AIDL API, do the following:
In either case, when you detect and process an unconsumed item in this manner, users will expect the app or game to communicate about it. We suggest that you display a dialog, message box, or notification that tells the user that they have successfully received their item.
Keep in mind that your app’s onResume() callback will be called when its process is started, as well as when it is brought to the foreground, regardless of which screen the app or game was in before it was paused. For example, a game with a home screen, a store screen, and a game screen might get its onResume() called from any of those screens. For an optimal user experience, we suggest you make it so your app or game handles unacknowledged or unconsumed items regardless of the screen you display when onResume() gets called. Thorough testing of this process in each screen is crucial to deliver a great user experience.
Finally, there is one more case your app must handle: when a user acquires an item from the Play Store app, and both the Play Store app and your app are visible at the same time with multi-window mode.
To support this scenario with the Google Play Billing Library, do the following:
PurchasesUpdatedListener
com.android.vending.billing.
PURCHASES_UPDATED
onPause()
Just as before, you should display a dialog, message box, or notification that tells the user that they have successfully received their item.
If you follow these steps, your app or game will be better prepared to robustly handle purchase flow interruptions and alternative purchase flows.
In June we announced the developer preview for a new Google Play Billing Library. Today, we are pleased to announce the official release of the Play Billing Library 1.0. This library simplifies the development process for Google Play Billing, allowing you to focus your efforts on your app.
Thank you for your valuable feedback and suggestions that helped us reach the 1.0 release. Watch the video below for a quick overview of the library's features.
With Play Billing, you can receive payments from users around the world via a payment system they trust and you can take advantage of features and reports in the Play Console to manage and earn more revenue.
If you have never implemented in-app billing in your apps, or you want to know what you can offer using Play Billing Library, read the In-app Billing Overview to familiarize yourself with concepts and terminology that make it easier for you to implement In-app Billing using the Play Billing Library.
Play Billing Library is available through Maven repository, and adding Play Billing Library to your project is simple as adding the following dependency into your app's build.gradle file:
build.gradle
dependencies { ... compile 'com.android.billingclient:billing:1.0' }
The Play Billing Library 1.0 automatically adds the com.android.vending.BILLING permission to your APK. This means you no longer need to manually include it in your application module's manifest.
com.android.vending.BILLING
These classes are the most important pieces when integrating the library into your Android app. The BillingClient is the bridge between your app and Google Play. You will use it for listing available products, starting the billing flow for in-app products or subscriptions (i.e. opening the payment interface), getting user purchases, and creating or modifying subscriptions.
BillingClient
When creating your BillingClient instance, you'll need to set a PurchasesUpdatedListener. This allows your app to receive updates from the In-app Billing API, including transaction results after the billing flow, as well as purchases completed outside of your app, e.g. user redeemed a Promo Code or bought a product on another device.
The following code demonstrates how you could override the onPurchasesUpdated() method of your PurchasesUpdatedListener:
@Override void onPurchasesUpdated(@BillingResponse int responseCode, List<Purchase> purchases) { if (responseCode == BillingResponse.OK && purchases != null) { for (Purchase purchase : purchases) { handlePurchase(purchase); } } else if (responseCode == BillingResponse.USER_CANCELED) { // Handle an error caused by a user canceling the purchase flow. } else { // Handle any other error codes. } }
You can implement the PurchasesUpdatedListener in your Activity or in any other class you want, according to your app's architecture. And here's the code for creating the BillingClient instance, and setting the PurchasesUpdatedListener:
mBillingClient = BillingClient.newBuilder(mContext) .setListener(mPurchasesUpdatedListener) .build();
To sell products in your app, first, you need to add them using the Play Console. For more details about how to add in-app products see the page Administering In-app Billing.
Attention: If this is a brand new app, before adding the products you must publish it to the alpha or beta distribution channel. For more information, see Draft Apps are No Longer Supported.
To get a list of product details with prices for current user, call querySkuDetailsAsync(). You must also specify a listener which implements the SkuDetailsResponseListener interface. You can then override the onSkuDetailsResponse() method which notifies the listener when the query finishes, as illustrated by the following sample code:
querySkuDetailsAsync()
SkuDetailsResponseListener
onSkuDetailsResponse()
List<String> skuList = new ArrayList<> (); skuList.add("premiumUpgrade"); skuList.add("gas"); SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); params.setSkusList(skuList).setType(SkuType.INAPP); mBillingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { @Override public void onSkuDetailsResponse(SkuDetailsResult result) { // Process the result. } })
After the user chooses a product to buy, you'll need to start the billing flow and handle the transaction result. To start a purchase request from your app, call the launchBillingFlow() method on the Play Billing Library client. You must call the launchBillingFlow() method (and all the other methods from BillingClient) from the UI thread.
The launchBillingFlow() method needs BillingFlowParams object that contains relevant data for completing the purchase, such as the product ID of the item to purchase and the product type (in this case, SkuType.INAPP). To get an instance of BillingFlowParams, construct it with newBuilder() method:
BillingFlowParams
SkuType.INAPP
newBuilder()
BillingFlowParams.Builder builder = BillingFlowParams .newBuilder() .setSku(skuId).setType(SkuType.INAPP); int responseCode = mBillingClient.launchBillingFlow(builder.build());
As we mentioned earlier, the transaction result will be sent to the onPurchasesUpdated() method. For details how to process the data received on onPurchasesUpdated() and how to handle a purchase, check the section Purchase an item in our training guide.
By default, all in-app products are managed. It means that Google Play tracks the product ownership and doesn't allow to buy multiple times. To be able to buy a product again, you must consume the product before it becomes available again.
It's common to implement consumption for in-app products which users may want to purchase multiple times, such as in-game currency or equipment. You typically don't want to implement consumption for in-app products that user purchases once and provide a permanent effect, such as a premium upgrade.
To consume a product, call the consumeAsync() method on the Play Billing Library client and pass in the purchaseToken String value returned when you made the purchase. The consumption result is returned via onConsumeResponse() method of the ConsumeResponseListener interface, that you must override to handle the consumption result.
purchaseToken
onConsumeResponse()
ConsumeResponseListener
The following example illustrates consuming a product using the associated purchaseToken:
ConsumeResponseListener listener = new ConsumeResponseListener() { @Override public void onConsumeResponse(@BillingResponse int responseCode, String outToken) { if (responseCode == BillingResponse.OK) { // Handle the success of the consume operation. // For example, increase the number of player's coins, // that provide temporary benefits } } }; mBillingClient.consumeAsync(purchaseToken, listener);
With a new library comes a refreshed sample! To help you to understand how to implement in-app billing in your app using the new Play Billing Library, we've rewritten the Trivial Drive sample from the ground up.
Since we released Trivial Drive back in 2013, many new features, devices, and platforms have been added to the Android ecosystem. To reflect this evolution, the Trivial Drive v2 sample now runs on Android TV and Android Wear.
Before integrating within your app, you can try the Play Billing Library with the codelab published during Google I/O 2017: Buy and Subscribe: Monetize your app on Google Play.
In this codelab, you will start with a simplified version of Trivial Drive V2 that lets users to "drive" and then you will add in-app billing to it. You'll learn how to integrate purchases and subscriptions as well as the best practices for developing reliable apps that handle purchases.
Get more info on the Play Billing Library and the official reference for classes and methods documentation on the Android Developers website. For a step-by-step guide to implementing the Play Billing Library in your project, visit the library's training class.
For more details about the Play Billing Library 1.0 release, check out the Releases Notes page, where you can find updates, bug fixes and behavior changes on the library since the Developer Preview release.
If you have issues or questions, file a bug report on the Google Issue Tracker, and for issues and suggestions on the sample (like a bug or a new feature), contact us on the Trivial Drive issues page.
For technical questions on implementation, library usage, and best practices, you can use the tags google-play and play-billing-library on StackOverflow or visit the communities on our Google+ page.
Many developers want to make money through their apps, but it's not always easy to deal with all the different types of payment methods. We launched the Google Play In-app Billing API v3 in 2013, helping developers offer in-app products and subscriptions within their apps. Year after year, we've added features to the API, like subscription renewal, upgrades and downgrades, free trials, introductory pricing, promotion codes, and more.
Based on your feedback, we’re pleased to announce the Play Billing Library - Developer Preview 1. This library aims to simplify the development process when it comes to billing, allowing you to focus your efforts on implementing logic specific to your app, such as application architecture and navigation structure. The library includes several convenient classes and features for you to use when integrating your Android apps with the In-app Billing API. The library also provides an abstraction layer on top of the Android Interface Definition Language (AIDL) service, making it easier for you to define the interface between your app and the In-app Billing API.
Starting with Play Billing Library Developer Preview release, the minimum supported API level is Android 2.2 (API level 8), and the minimum supported In-app Billing API is version 3.
In-app billing relies on the Google Play Store, which handles the communication between your app and Google's Play billing service. To use Google Play billing features, your app must request the com.android.vending.BILLING permission in your AndroidManifest.xml file.
AndroidManifest.xml
To use the library, add the following dependency in your build.gradle file:
dependencies { ... compile 'com.android.billingclient:billing:dp-1' }
After this quick setup process, you're ready to start using the Play Billing Library in your app and can connect to the In-app Billing API, query for available products, start the purchase flow, and more.
If you are looking for a step-by-step guide about how to sell in-app products from your app using the Play Billing Library, check out our new training class, explaining how to prepare your application, add products for purchase, start purchase flow and much more.
We look forward to hearing your feedback about this new library. Visit the Play Billing Library site, the library reference, and the new version of the Trivial Drive sample. If you have issues or questions, file a bug report on the Google Issue Tracker, and for issues and suggestions on the sample, contact us on the Trivial Drive issues page.
For technical questions on implementation, library usage, and best practices, you can use the tags google-play and play-billing-library on Stackoverflow or visit the community pages on our Google+ page.
Back in 2012, we introduced free trials support for Android app subscriptions. A free trial runs for a period of time that you set and then automatically converts to a full subscription based on the subscription's billing interval and price. Google Play supports free trials for all subscription types. Check out Free trials in our documentation for more details.
This feature is an important tool for user conversion because the user can try your app or game before committing to paying. To help you track the subscription status better, we are adding a third "paymentState" value to the Purchases.subscriptions API (on Google Play Developer API) to represent that the user is in a free trial. Possible values are:
Since there is a new possible value, it is necessary to check how your back end is handling the paymentState parameter. If you are doing something like this, you potentially could have a problem:
// WARNING: Don't do this! if (paymentState == 1) { // User is in normal state } else { // Handle user in grace period # this would now be a bug }
As a best practice, and to avoid issues on future updates, we recommend checking specifically for each possible case, like this:
if (paymentState == 0) { // Subscriber with payment pending } else if (paymentState == 1) { // Subscriber in good standing (paid) } else if (paymentState == 2) { // Subscriber in free trial }
You can check the Purchases.subscriptions documentation for more details. And if you're not offering free trials in your app or game, don't miss the chance to increase user conversions by letting them have a taste of your app - check out our documentation on Free trials.
In-app Billing version 3 is available now and lets you sell both in-app items and (since February 2013) subscriptions, including subscriptions with free trials. It is supported by Android 2.2+ devices running the latest version of the Google Play Store (over 90% of active devices).
Bundle bundle = mService.getBuyIntent(3, "com.example.myapp", MY_SKU, ITEM_TYPE_INAPP, developerPayload); PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT); if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { // Start purchase flow (this brings up the Google Play UI). // Result will be delivered through onActivityResult(). startIntentSenderForResult(pendingIntent, RC_BUY, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0)); }
public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == RC_BUY) { int responseCode = data.getIntExtra(RESPONSE_CODE); String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA); String signature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE); // handle purchase here (for a permanent item like a premium upgrade, // this means dispensing the benefits of the upgrade; for a consumable // item like "X gold coins", typically the application would initiate // consumption of the purchase here) } }
Bundle bundle = mService.getPurchases(3, mContext.getPackageName(), ITEM_TYPE_INAPP); if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { ArrayList mySkus, myPurchases, mySignatures; mySkus = bundle.getStringArrayList(RESPONSE_INAPP_ITEM_LIST); myPurchases = bundle.getStringArrayList(RESPONSE_INAPP_PURCHASE_DATA_LIST); mySignatures = bundle.getStringArrayList(RESPONSE_INAPP_PURCHASE_SIGNATURE_LIST); // handle items here }
Bundle bundle = mService.getSkuDetails(3, "com.example.myapp", ITEM_TYPE_INAPP, skus); // skus is a Bundle with the list of SKUs to query if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { List detailsList = bundle.getStringArrayList(RESPONSE_SKU_DETAILS_LIST); for (String details : detailsList) { // details is a JSON string with // SKU details (title, description, price, ...) } }