Implement Google Play Billing

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. You will need to read additional documents, mentioned at the end of this page, to learn how to add in-app product-specific functionality to your app.

Before reading this page, do the following:

  1. Read the Google Play Billing Overview to familiarize yourself with important concepts and terms.
  2. Configure your in-app products using the Google Play Console:

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:

Figure 1. Opening screen of Trivial Drive app.

Steps to add Google Play Billing to an app

The steps to add Google Play Billing to an app are:

  1. Update your app's dependencies.
  2. Connect to Google Play.
  3. Query for in-app product details.
  4. Enable the purchase of an in-app product.
  5. Query for purchased items.
  6. 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:

  1. Call the newBuilder() method to create an instance of BillingClient class also known as the Play Billing Library client. You must also call the setListener() method and pass it a reference to an instance of PurchasesUpdatedListener to receive updates on purchases initiated by your app, as well as those initiated by the Google Play Store.

  2. Establish a connection to Google Play. The setup process is asynchronous and you must implement a BillingClientStateListener to receive a callback once the setup of the client is complete and it’s ready to make further requests.

  3. 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 the startConnection() 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

List skuList = 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 will be 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:

Figure 2. The Trivial Drive in-app products screen.

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 3. Google Play purchase screen for a one-time product.

Figure 4 shows a purchase screen for a subscription:

Figure 4. Google Play 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, List 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 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.

Figure 5. Google Play success screen.

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 will also be emailed a receipt of the transaction containing an order ID or a unique ID of the transaction. Users will receive an email with 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:

  1. 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.

  2. After you get the token from the app:

    1. 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.products for a one-time product purchase or Purchases.subscriptions for a subscription). The GET request includes the app package name, product ID, and a token (purchase token).

    2. Google Play returns the purchase details.

    3. The secure backend server verifies that the order ID is a unique value that doesn’t represent a previous purchase.

    4. 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.

    5. (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 linkedPurchaseToken field. The linkedPurchaseToken field in a Purchases.subscriptions resource contains the token of the previous, or “originating” purchase. For more about linkedPurchaseToken, refer to Purchases.subscriptions).

    6. 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 will 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

  1. A user buys a one-time product, such as extra gas for a driving game.
  2. The app sends the purchase token to the secure backend server for verification.
  3. The server is temporarily down.
  4. The app recognizes that the server is down and notifies the user that there’s a problem with the purchase.
  5. The Android app retries sending the purchase token to the secure backend server, and finishes the purchase as soon as the server is restored.
  6. The app releases the content.

Handling multiple devices

  1. A user buys a subscription on their Android phone.
  2. The app sends the purchase token to the secure backend server for verification.
  3. The server verifies the purchase token.
  4. The app releases the content.
  5. The user switches to an Android tablet to use the subscription.
  6. The app on the new device queries for an updated list of purchases.
  7. 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.

You will want to call queryPurchases() at least twice in your code:

  • Call queryPurchases() every time your app launches so that you can restore any purchases that a user has made since the app last stopped.
  • Call queryPurchases() in your onResume() method since 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.