This document explains how to add Google Play Billing into your app using the Google Play Library. Specifically, this document covers how to code Google Play Billing functionality common to both one-time products and subscriptions. To learn how to add in-app product-specific functionality to your app, read the documents listed at the end of this page.
Before reading this page, do the following:
- Read the Google Play Billing Overview to familiarize yourself with important concepts and terms.
- Configure your in-app products using the Google Play Console:
- To configure a one-time product, refer to Create a managed product.
- To configure a subscription, refer to Create a subscription.
About the code snippets
This guide uses code snippets from the TrivialDrive v2 sample app. This sample shows how to use Play Billing Library to implement in-app product and subscription purchases for a driving game. The app demonstrates how to list the available products, start a purchase flow, record product consumption, and everything else you need to know to add Google Play Billing into your app. Figure 1 shows the opening screen of this app:
Steps to add Google Play Billing to an app
The steps to add Google Play Billing to an app are:
- Update your app's dependencies.
- Connect to Google Play.
- Query for in-app product details.
- Enable the purchase of an in-app product.
- Query for purchased items.
- Add one-time product-specific or subscription-specific code (covered on separate pages).
Update your app's dependencies
Add the following line to the dependencies section of the build.gradle file
for your app:
dependencies {
...
implementation 'com.android.billingclient:billing:1.1'
}
To ensure you are using the current version of the billing client, refer to the Google Play Billing Library release notes.
Connect to Google Play
Before you can make Google Play Billing requests, you must first establish a connection to Google Play using the following steps:
Call the
newBuilder()method to create an instance ofBillingClientclass also known as the Play Billing Library client. You must also call thesetListener()method and pass it a reference to an instance ofPurchasesUpdatedListenerto receive updates on purchases initiated by your app, as well as those initiated by the Google Play Store.Establish a connection to Google Play. The setup process is asynchronous and you must implement a
BillingClientStateListenerto receive a callback once the setup of the client is complete and it’s ready to make further requests.Override the
onBillingServiceDisconnected()callback method and implement your own retry policy to handle lost connections to Google Play in the event the client loses connection. For example, the Play Billing Library client may lose its connection if the Play Store service is updating in the background. The Play Billing Library client must call thestartConnection()method to restart the connection before making further requests.
The following code sample demonstrates how to start a connection and then test that it's ready to use:
Kotlin
lateinit private var billingClient: BillingClient
...
billingClient = BillingClient.newBuilder(context).setListener(this).build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(@BillingResponse billingResponseCode: Int) {
if (billingResponseCode == BillingResponse.OK) {
// The billing client is ready. You can query purchases here.
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
Java
// create new Person
private BillingClient mBillingClient;
...
mBillingClient = BillingClient.newBuilder(mActivity).setListener(this).build();
mBillingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(@BillingResponse int billingResponseCode) {
if (billingResponseCode == BillingResponse.OK) {
// The billing client is ready. You can query purchases here.
}
}
@Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
Query for in-app product details
The unique Product IDs you created when configuring your in-app products are
used to asynchronously query Google Play for in-app product details. To query
Google Play for in-app product details, call the
querySkuDetailsAsync() method. When
calling this method, pass an instance of
SkuDetailsParams
that specifies a list of products ID strings and a SkuType. The SkuType can
be either SkuType.INAPP for one-time products, or SkuType.SUBS, for
subscriptions.
Notice that the Google Play Billing Library uses the SkuType of INAPP
to indicate a one-time product.
To handle the result of the asynchronous operation, 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:
Kotlin
} val skuList = ArrayList() skuList.add("premium_upgrade") skuList.add("gas") val params = SkuDetailsParams.newBuilder() params.setSkusList(skuList).setType(SkuType.INAPP) billingClient.querySkuDetailsAsync(params.build(), { responseCode, skuDetailsList -> // Process the result. })
Java
ListskuList = new ArrayList<> (); skuList.add("premium_upgrade"); skuList.add("gas"); SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); params.setSkusList(skuList).setType(SkuType.INAPP); mBillingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { @Override public void onSkuDetailsResponse(int responseCode, List skuDetailsList) { // Process the result. } });
Your app should maintain its own product ID list either by bundling that list with your APK or querying it from your own secure backend server.
If the request is successful, the response code is BillingResponse.OK. To
view all of the possible response codes from Google Play, see
BillingClient.BillingResponse Reference.
The Play Billing Library stores the query results in a List of
SkuDetails
objects. You can then call a variety of methods on each of the SkuDetails
objects in the list to view relevant information about an in-app product, such
as its price or description. To view the available product detail information
, see the list of methods in the
SkuDetails
class.
The following example shows how to retrieve the prices for in-app products using
the
SkuDetails
object returned by the previous code snippet:
Kotlin
if (responseCode == BillingResponse.OK && skuDetailsList != null) {
for (skuDetails in skuDetailsList) {
val sku = skuDetails.sku
val price = skuDetails.price
if ("premium_upgrade" == sku) {
premiumUpgradePrice = price
} else if ("gas" == sku) {
Java
if (responseCode == BillingResponse.OK
&& skuDetailsList != null) {
for (SkuDetails skuDetails : skuDetailsList) {
String sku = skuDetails.getSku();
String price = skuDetails.getPrice();
if ("premium_upgrade".equals(sku)) {
mPremiumUpgradePrice = price;
} else if ("gas".equals(sku)) {
mGasPrice = price;
}
}
}
Retrieving a product’s price is an important step before a user can purchase a product because the price is different for each user based on their country of origin. The Trivial Drive app displays all the in-app products as a list as shown in Figure 2:
Enable the purchase of an in-app product
Some Android phones might have an older version of the Play Store app that
doesn't support certain products types, such as subscriptions. Therefore, before
your app enters the billing flow, call the
isFeatureSupported() method to check that the device supports the products you want
to sell. To see a list of product types, refer to
BillingClient.FeatureType.
To start a purchase request from your app, call the
launchBillingFlow() method
from the UI thread. Pass a reference to a
BillingFlowParams
object containing the relevant data to complete the purchase, such as the
product ID (skuId) of the item and product type (SkuType.INAPP for a
one-time product or SkuType.SUBS for a subscription). To get an instance of
BillingFlowParams
, use the
BillingFlowParams.Builder
class:
Kotlin
val flowParams = BillingFlowParams.newBuilder()
.setSku(skuId)
.setType(SkuType.INAPP) // SkuType.SUB for subscription
.build()
val responseCode = billingClient.launchBillingFlow(activity, flowParams)
Java
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSku(skuId)
.setType(SkuType.INAPP) // SkuType.SUB for subscription
.build();
int responseCode = mBillingClient.launchBillingFlow(flowParams);
When you call the
launchBillingFlow()
method, the system displays the Google Play purchase screen. Figure 3 shows a
purchase screen for a one-time product:
Figure 4 shows a purchase screen for a subscription:
The
launchBillingFlow()
method returns one of several response codes listed in
BillingClient.BillingResponse.
Google Play calls the
onPurchasesUpdated()
method to deliver the result of the purchase operation to a listener that
implements the
PurchasesUpdatedListener interface. The listener is specified using the
setListener() method as demonstrated earlier
in the Connect to Google Play section.
You must implement the
onPurchasesUpdated()
method to handle possible response codes. The following code snippet show how to
override the
onPurchasesUpdated()
method:
Kotlin
override fun onPurchasesUpdated(@BillingResponse responseCode: Int, purchases: List?) { if (responseCode == BillingResponse.OK && purchases != null) { for (purchase in purchases) { handlePurchase(purchase) } } else if (responseCode == BillingResponse.USER_CANCELED) { // Handle an error caused by a user cancelling the purchase flow. } else { // Handle any other error codes. } }
Java
@Override void onPurchasesUpdated(@BillingResponse int responseCode, Listpurchases) { 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 cancelling the purchase flow. } else { // Handle any other error codes. } }
Successful purchases generate a Google Play success screen similar to the screen in Figure 5.
Successful purchases also generate a purchase token, which is a unique identifier representing the user and the product ID for the in-app product they purchased. Your apps can store the purchase token locally or, ideally, pass it to your secure backend server where it can be used to verify the purchase and protect against fraud. The purchase token is unique for every one-time product purchase. However, because subscriptions are purchased once and automatically renewed on a regular billing period, the purchase token for subscriptions stays the same for each billing period.
The user is also emailed a receipt of the transaction containing an order ID or a unique ID of the transaction. Users receive an email with a unique order ID for each one-time product purchase, and also for the initial subscription purchase and subsequent recurring automatic renewals. You can use the order ID to manage refunds in the Google Play Console. For further details, refer to to View and refund your app’s orders and subscriptions.
Verify a purchase
You should verify purchase details that your app receives in
onPurchasesUpdated()
before providing the user access to what they have purchased.
Verify a purchase on a server
By implementing purchase verification logic on a server, you can protect your app from attackers who try to reverse-engineer your APK file and disable its verification logic. To verify purchase details on a secure backend server, complete the following steps:
From you app, send the purchase token and user account credential to your secure backend server. The secure backend server should associate the purchase with the user after verification has succeeded.
After you get the token from the app:
Use the Subscriptions and In-App Purchases portion of the Google Play Developer API to perform a GET request to retrieve the purchase details from Google Play (
Purchases.productsfor a one-time product purchase orPurchases.subscriptionsfor a subscription). The GET request includes the app package name, product ID, and a token (purchase token).Google Play returns the purchase details.
The secure backend server verifies that the order ID is a unique value that doesn’t represent a previous purchase.
The secure backend server uses the user account credential received in step 1 to associate the purchase token with the user of the app instance where the purchase was made.
(optional) If you are validating a subscription and the subscription is being upgraded, downgraded, or the user has re-subscribed before the subscription has lapsed, check the
linkedPurchaseTokenfield. ThelinkedPurchaseTokenfield in aPurchases.subscriptionsresource contains the token of the previous, or “originating” purchase. For more aboutlinkedPurchaseToken, refer toPurchases.subscriptions).The in-app product is made available to the user.
Verify a purchase on a device
If you cannot run your own server, you can still validate purchase details within your Android app.
To help ensure the integrity of the transaction information that is sent to your
application, Google Play signs the JSON string that contains the response data
for a purchase. Google Play uses the private key that is associated with your
application in the Play Console to create this signature. The Play Console
generates an RSA key pair for each application. You get this response JSON
using the getOriginalJson()
method within the
Purchase
class.
The Base64-encoded RSA public key that is generated by Google Play is in binary encoded, X.509 subjectPublicKeyInfo DER SEQUENCE format. It is the same public key that is used with Google Play licensing.
When your application receives this signed response, you can use the public key portion of your RSA key pair to verify the signature. By performing signature verification, you can detect any responses that have been tampered with or that have been spoofed.
You should obfuscate your Google Play public key and Google Play Billing code so it's difficult for an attacker to reverse-engineer security protocols and other application components. At a minimum, we recommend that you run an obfuscation tool like Proguard on your code. To obfuscate your code using Proguard, you must add the following line to your Proguard configuration file:
-keep class com.android.vending.billing.**
After obfuscating your Google Play public key and In-app Billing code, you're ready to have your app validate purchase details. When your app verifies a signature, ensure that your app's key signed the JSON data contained in that signature.
Keep purchases up-to-date
It is possible to lose track of what purchases a user has made. Following are two scenarios where your app could lose track of purchases and where querying for purchases is important.
Handling server outages
- A user buys a one-time product, such as extra gas for a driving game.
- The app sends the purchase token to the secure backend server for verification.
- The server is temporarily down.
- The app recognizes that the server is down and notifies the user that there’s a problem with the purchase.
- The Android app retries sending the purchase token to the secure backend server, and finishes the purchase as soon as the server is restored.
- The app releases the content.
Handling multiple devices
- A user buys a subscription on their Android phone.
- The app sends the purchase token to the secure backend server for verification.
- The server verifies the purchase token.
- The app releases the content.
- The user switches to an Android tablet to use the subscription.
- The app on the new device queries for an updated list of purchases.
- The app recognizes the subscription and grants access to it on the tablet.
Query cached purchases
To retrieve information about purchases that a user makes from your app, call
the
queryPurchases() method with the purchase type (SkuType.INAPP or SkuType.SUBS)
on the Play Billing Library client. For example:
PurchasesResult purchasesResult = mBillingClient.queryPurchases(SkuType.INAPP);
Google Play returns the purchases made by the user account logged in to the
device. If the request is successful, the Play Billing Library stores the query
results in a List of Purchase
objects.
To retrieve the list, call the
getPurchasesList() method on the
PurchasesResult
object. You can then call a variety of methods on the Purchase
object to view relevant information about the item, such as its purchase state
or time. To view the types of product detail information that are available, see
the list of methods in the
Purchase class.
Call
queryPurchases() at least twice in your code:
- Every time your app launches so that you can restore any purchases that a user has made since the app last stopped.
- In your
onResume()method because a user can make a purchase when your app is in the background (for example, redeeming a promo code in Play Store app).
Calling
queryPurchases() on startup and resume guarantees that your app finds out about all
purchases and redemptions the user may have made while the app wasn't running.
Furthermore, if a user makes a purchase while the app is running and your app
misses it for any reason, your app still finds out about the purchase the next
time the activity resumes and calls
queryPurchases().
Query most recent purchases
The
queryPurchases() method uses a cache of the Google Play Store app without
initiating a network request. If you need to check the most recent purchase made
by the user for each product ID, you can use the
queryPurchaseHistoryAsync()
method and pass the purchase type and a
PurchaseHistoryResponseListener to handle the query result.
queryPurchaseHistoryAsync()
returns the most recent purchase made by the user for each product ID, even if
that purchase is expired, cancelled, or consumed. Use the
queryPurchases() method whenever possible, as it uses the local cache, instead
of the
queryPurchaseHistoryAsync()
method. You could combine
queryPurchaseHistoryAsync()
with a Refresh button allowing users to update their list of purchases.
The following code demonstrates how you can override the
onPurchaseHistoryResponse()
method:
Kotlin
billingClient.queryPurchaseHistoryAsync(SkuType.INAPP, { responseCode, purchasesList ->
if (responseCode == BillingResponse.OK && purchasesList != null) {
for (purchase in purchasesList) {
// Process the result.
}
}
})
Java
mBillingClient.queryPurchaseHistoryAsync(SkuType.INAPP,
new PurchaseHistoryResponseListener() {
@Override
public void onPurchaseHistoryResponse(@BillingResponse int responseCode,
List purchasesList) {
if (responseCode == BillingResponse.OK
&& purchasesList != null) {
for (Purchase purchase : purchasesList) {
// Process the result.
}
}
}
});
Next steps
After you have added code to allow users to buy a one-time product or subscription, you should learn how to add code to cover product-specific scenarios.
If you are adding Google Play Billing to support one-time products, read Add one-time product-specific features.
If you are adding Google Play Billing to support subscriptions, read Add Subscription-specific features.


