Implementing In-app Billing (IAB Version 2)

The In-app Billing Version 2 API has been deprecated in favor of the Version 3 API. If your app is using In-app Billing, please make sure that it is using the Version 3 API. If your app is still using the Version 2 API, you must migrate to the Version 3 API as soon as possible.

We plan to turn off the In-app Billing Version 2 service on January 27, 2015, after which time users will no longer be able to purchase in-app items and subscriptions through the Version 2 API. We strongly encourage and recommend you migrate your apps to use Version 3 API by November 2014, to provide ample time for users to update their apps to the new version.

For more information, please see the Help Center article. For common questions about transitioning your implementation to In-app Billing Version 3, please see Migration Considerations.

This document helps you implement In-app Billing Version 2 by stepping through the primary implementation tasks, using the sample application as an example.

Before you implement in-app billing in your own application, be sure that you read Overview of In-app Billing Version 2 and Security and Design. These documents provide background information that will make it easier for you to implement in-app billing.

To implement in-app billing in your application, you need to do the following:

  1. Download the in-app billing sample application.
  2. Add the IMarketBillingService.aidl file to your project.
  3. Update your AndroidManifest.xml file.
  4. Create a Service and bind it to the MarketBillingService so your application can send billing requests and receive billing responses from Google Play.
  5. Create a BroadcastReceiver to handle broadcast intents from Google Play.
  6. Create a security processing component to verify the integrity of the transaction messages that are sent by Google Play.
  7. Modify your application code to support in-app billing.

Downloading the Sample Application

The in-app billing sample application shows you how to perform several tasks that are common to all in-app billing implementations, including:

  • Sending in-app billing requests to Google Play.
  • Handling synchronous responses from Google Play.
  • Handling broadcast intents (asynchronous responses) from Google Play.
  • Using in-app billing security mechanisms to verify the integrity of billing responses.
  • Creating a user interface that lets users select items for purchase.

The sample application includes an application file (Dungeons.java), the AIDL file for the MarketBillingService (IMarketBillingService.aidl), and several classes that demonstrate in-app billing messaging. It also includes a class that demonstrates basic security tasks, such as signature verification.

Table 1 lists the source files that are included with the sample application.

Table 1. In-app billing sample application source files.

File Description
IMarketBillingService.aidl Android Interface Definition Library (AIDL) file that defines the IPC interface to Google Play's in-app billing service (MarketBillingService).
Dungeons.java Sample application file that provides a UI for making purchases and displaying purchase history.
PurchaseDatabase.java A local database for storing purchase information.
BillingReceiver.java A BroadcastReceiver that receives asynchronous response messages (broadcast intents) from Google Play. Forwards all messages to the BillingService.
BillingService.java A Service that sends messages to Google Play on behalf of the application by connecting (binding) to the MarketBillingService.
ResponseHandler.java A Handler that contains methods for updating the purchases database and the UI.
PurchaseObserver.java An abstract class for observing changes related to purchases.
Security.java Provides various security-related methods.
Consts.java Defines various Google Play constants and sample application constants. All constants that are defined by Google Play must be defined the same way in your application.
Base64.java and Base64DecoderException.java Provides conversion services from binary to Base64 encoding. The Security class relies on these utility classes.

The in-app billing sample application is available as a downloadable component of the Android SDK. To download the sample application component, launch the Android SDK Manager and then select the Google Market Billing package component (see figure 1), and click Install Selected to begin the download.

Figure 1. The Google Market Billing package contains the sample application and the AIDL file.

When the download is complete, the Android SDK Manager saves the component into the following directory:

<sdk>/extras/google/market_billing/

If you want to see an end-to-end demonstration of in-app billing before you integrate in-app billing into your own application, you can build and run the sample application. Building and running the sample application involves three tasks:

  • Configuring and building the sample application.
  • Uploading the sample application to Google Play.
  • Setting up test accounts and running the sample application.

Note: Building and running the sample application is necessary only if you want to see a demonstration of in-app billing. If you do not want to run the sample application, you can skip to the next section, Adding the AIDL file to your project.

Configuring and building the sample application

Before you can run the sample application, you need to configure it and build it by doing the following:

  1. Add your app's public key to the sample application code.

    This enables the application to verify the signature of the transaction information that is returned from Google Play. To add your public key to the sample application code, do the following:

    1. Log in to your Google Play Developer console.
    2. On the upper left part of the page, All Applications, click the application name..
    3. On the Edit Profile page, scroll down to the Licensing & In-app Billing panel.
    4. Copy your public key.
    5. Open src/com/example/dungeons/Security.java in the editor of your choice.

      You can find this file in the sample application's project folder.

    6. Add your public key to the following line of code:

      String base64EncodedPublicKey = "your public key here";

    7. Save the file.
  2. Change the package name of the sample application.

    The current package name is com.example.dungeons. Google Play does not let you upload applications with package names that contain com.example, so you must change the package name to something else.

  3. Build the sample application in release mode and sign it.

    To learn how to build and sign applications, see Building and Running.

Uploading the sample application

After you build a release version of the sample application and sign it, you need to upload it as a draft to the Google Play Developer Console. You also need to create a product list for the in-app items that are available for purchase in the sample application. The following instructions show you how to do this.

Caution: Draft applications are no longer supported. To test an application, publish it in the alpha or beta channels. For more information, see Draft Apps are No Longer Supported.

  1. Upload the release version of the sample application to Google Play.

    Do not publish the sample application; leave it as an unpublished draft application. The sample application is for demonstration purposes only and should not be made publicly available on Google Play. To learn how to upload an application to Google Play, see Uploading applications.

  2. Create a product list for the sample application.

    The sample application lets you purchase two items: a two-handed sword (sword_001) and a potion (potion_001). We recommend that you set up your product list so that sword_001 has a purchase type of "Managed per user account" and potion_001 has a purchase type of "Unmanaged" so you can see how these two purchase types behave. To learn how to set up a product list, see Creating a Product List.

    Note: You must publish the items in your product list (sword_001 and potion_001) even though you are not publishing the sample application. Also, you must have a Google payments merchant account to add items to the sample application's product list.

Running the sample application

You cannot run the sample application in the emulator. You must install the sample application onto a device to run it. To run the sample application, do the following:

  1. Make sure you have at least one test account registered under your Google Play publisher account.

    You cannot purchase items from yourself, so you need to create at least one test account that you can use to purchase items in the sample application. To learn how to set up a test account, see Setting up Test Accounts.

  2. Verify that your device is running a supported version of the Google Play application or the MyApps application.

    If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Google Play application. To learn how to check the version of the Google Play application, see Updating Google Play.

  3. Install the application onto your device.

    Even though you uploaded the application to Google Play, the application is not published, so you cannot download it from Google Play to a device. Instead, you must install the application onto your device. To learn how to install an application onto a device, see Running on a device.

  4. Make one of your test accounts the primary account on your device.

    The primary account on your device must be one of the test accounts that you registered on the Google Play Developer Console. If the primary account on your device is not a test account, you must do a factory reset of the device and then sign in with one of your test accounts. To perform a factory reset, do the following:

    1. Open Settings on your device.
    2. Touch Privacy.
    3. Touch Factory data reset.
    4. Touch Reset phone.
    5. After the phone resets, be sure to sign in with one of your test accounts during the device setup process.
  5. Run the application and purchase the sword or the potion.

    When you use a test account to purchase items, the test account is billed through Google payments and your Google payments merchant account receives a payout for the purchase. Therefore, you may want to refund purchases that are made with test accounts, otherwise the purchases will show up as actual payouts to your merchant account.

Note: Debug log messages are turned off by default in the sample application. You can turn them on by setting the variable DEBUG to true in the Consts.java file.

Adding the AIDL file to your project

The sample application contains an Android Interface Definition Language (AIDL) file, which defines the interface to Google Play's in-app billing service (MarketBillingService). When you add this file to your project, the Android build environment creates an interface file (IMarketBillingService.java). You can then use this interface to make billing requests by invoking IPC method calls.

If you are using the ADT plug-in with Eclipse, you can just add this file to your /src directory. Eclipse will automatically generate the interface file when you build your project (which should happen immediately). If you are not using the ADT plug-in, you can put the AIDL file into your project and use the Ant tool to build your project so that the IMarketBillingService.java file gets generated.

To add the IMarketBillingService.aidl file to your project, do the following:

  1. Create the following directory in your application's /src directory:

    com/android/vending/billing/

  2. Copy the IMarketBillingService.aidl file into the sample/src/com/android/vending/billing/ directory.
  3. Build your application.

You should now find a generated interface file named IMarketBillingService.java in the gen folder of your project.

Updating Your Application's Manifest

In-app billing relies on the Google Play application, which handles all communication between your application and the Google Play server. To use the Google Play application, your application must request the proper permission. You can do this by adding the com.android.vending.BILLING permission to your AndroidManifest.xml file. If your application does not declare the in-app billing permission, but attempts to send billing requests, Google Play will refuse the requests and respond with a RESULT_DEVELOPER_ERROR response code.

In addition to the billing permission, you need to declare the BroadcastReceiver that you will use to receive asynchronous response messages (broadcast intents) from Google Play, and you need to declare the Service that you will use to bind with the IMarketBillingService and send messages to Google Play. You must also declare intent filters for the BroadcastReceiver so that the Android system knows how to handle the broadcast intents that are sent from the Google Play application.

For example, here is how the in-app billing sample application declares the billing permission, the BroadcastReceiver, the Service, and the intent filters. In the sample application, BillingReceiver is the BroadcastReceiver that handles broadcast intents from the Google Play application and BillingService is the Service that sends requests to the Google Play application.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.dungeons"
  android:versionCode="1"
  android:versionName="1.0">

  <uses-permission android:name="com.android.vending.BILLING" />

  <application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".Dungeons" android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>

    <service android:name="BillingService" />

    <receiver android:name="BillingReceiver">
      <intent-filter>
        <action android:name="com.android.vending.billing.IN_APP_NOTIFY" />
        <action android:name="com.android.vending.billing.RESPONSE_CODE" />
        <action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" />
      </intent-filter>
    </receiver>

  </application>
</manifest>

Creating a Local Service

Your application must have a local Service to facilitate messaging between your application and Google Play. At a minimum, this service must do the following:

  • Bind to the MarketBillingService.
  • Send billing requests (as IPC method calls) to the Google Play application. The five types of billing requests include:
    • CHECK_BILLING_SUPPORTED requests
    • REQUEST_PURCHASE requests
    • GET_PURCHASE_INFORMATION requests
    • CONFIRM_NOTIFICATIONS requests
    • RESTORE_TRANSACTIONS requests
  • Handle the synchronous response messages that are returned with each billing request.

Binding to the MarketBillingService

Binding to the MarketBillingService is relatively easy if you've already added the IMarketBillingService.aidl file to your project. The following code sample shows how to use the bindService() method to bind a service to the MarketBillingService. You could put this code in your service's onCreate() method.

try {
  boolean bindResult = mContext.bindService(
    new Intent("com.android.vending.billing.MarketBillingService.BIND"), this,
    Context.BIND_AUTO_CREATE);
  if (bindResult) {
    Log.i(TAG, "Service bind successful.");
  } else {
    Log.e(TAG, "Could not bind to the MarketBillingService.");
  }
} catch (SecurityException e) {
  Log.e(TAG, "Security exception: " + e);
}

After you bind to the service, you need to create a reference to the IMarketBillingService interface so you can make billing requests via IPC method calls. The following code shows you how to do this using the onServiceConnected() callback method.

/**
  * The Android system calls this when we are connected to the MarketBillingService.
  */
  public void onServiceConnected(ComponentName name, IBinder service) {
    Log.i(TAG, "MarketBillingService connected.");
    mService = IMarketBillingService.Stub.asInterface(service);
  }

You can now use the mService reference to invoke the sendBillingRequest() method.

For a complete implementation of a service that binds to the MarketBillingService, see the BillingService class in the sample application.

Sending billing requests to the MarketBillingService

Now that your Service has a reference to the IMarketBillingService interface, you can use that reference to send billing requests (via IPC method calls) to the MarketBillingService. The MarketBillingService IPC interface exposes a single public method (sendBillingRequest()), which takes a single Bundle parameter. The Bundle that you deliver with this method specifies the type of request you want to perform, using various key-value pairs. For instance, one key indicates the type of request you are making, another indicates the item being purchased, and another identifies your application. The sendBillingRequest() method immediately returns a Bundle containing an initial response code. However, this is not the complete purchase response; the complete response is delivered with an asynchronous broadcast intent. For more information about the various Bundle keys that are supported by the MarketBillingService, see In-app Billing Service Interface.

You can use the sendBillingRequest() method to send five types of billing requests. The five request types are specified using the BILLING_REQUEST Bundle key. This Bundle key can have the following five values:

  • CHECK_BILLING_SUPPORTED—verifies that the Google Play application supports in-app billing and the version of the In-app Billing API available.
  • REQUEST_PURCHASE—sends a purchase request for an in-app item.
  • GET_PURCHASE_INFORMATION—retrieves transaction information for a purchase or refund.
  • CONFIRM_NOTIFICATIONS—acknowledges that you received the transaction information for a purchase or refund.
  • RESTORE_TRANSACTIONS—retrieves a user's transaction history for managed purchases.

To make any of these billing requests, you first need to build an initial Bundle that contains the three keys that are required for all requests: BILLING_REQUEST, API_VERSION, and PACKAGE_NAME. The following code sample shows you how to create a helper method named makeRequestBundle() that does this.

protected Bundle makeRequestBundle(String method) {
  Bundle request = new Bundle();
  request.putString(BILLING_REQUEST, method);
  request.putInt(API_VERSION, 1);
  request.putString(PACKAGE_NAME, getPackageName());
  return request;

To use this helper method, you pass in a String that corresponds to one of the five types of billing requests. The method returns a Bundle that has the three required keys defined. The following sections show you how to use this helper method when you send a billing request.

Important: You must make all in-app billing requests from your application's main thread.

Verifying that in-app billing is supported (CHECK_BILLING_SUPPPORTED)

The following code sample shows how to verify whether the Google Play application supports in-app billing and confirm what version of the API it supports. In the sample, mService is an instance of the MarketBillingService interface.

/**
* Request type is CHECK_BILLING_SUPPORTED
*/
  Bundle request = makeRequestBundle("CHECK_BILLING_SUPPORTED");
  Bundle response = mService.sendBillingRequest(request);
  // Do something with this response.
}

The makeRequestBundle() method constructs an initial Bundle, which contains the three keys that are required for all requests: BILLING_REQUEST, API_VERSION, and PACKAGE_NAME. If you are offering subscriptions in your app, set the API_VERSION key to a value of "2", to confirm that In-app Billing v2 is available. For an example, see Subscriptions.

The CHECK_BILLING_SUPPORTED request returns a synchronous Bundle response, which contains only a single key: RESPONSE_CODE. The RESPONSE_CODE key can have the following values:

  • RESULT_OK—the spedified version of in-app billing is supported.
  • RESULT_BILLING_UNAVAILABLE—in-app billing is not available because the API version you specified is not recognized or the user is not eligible to make in-app purchases (for example, the user resides in a country that prohibits in-app purchases).
  • RESULT_ERROR—there was an error connecting with the Google Play application.
  • RESULT_DEVELOPER_ERROR—the application is trying to make an in-app billing request but the application has not declared the com.android.vending.BILLING permission in its manifest. Can also indicate that an application is not properly signed, or that you sent a malformed request.

The CHECK_BILLING_SUPPORTED request does not trigger any asynchronous responses (broadcast intents).

We recommend that you invoke the CHECK_BILLING_SUPPORTED request within a RemoteException block. When your code throws a RemoteException it indicates that the remote method call failed, which means that the Google Play application is out of date and needs to be updated. In this case, you can provide users with an error message that contains a link to the Updating Google Play Help topic.

The sample application demonstrates how you can handle this error condition (see DIALOG_CANNOT_CONNECT_ID in Dungeons.java).

Making a purchase request (REQUEST_PURCHASE)

To make a purchase request you must do the following:

  • Send the REQUEST_PURCHASE request.
  • Launch the PendingIntent that is returned from the Google Play application.
  • Handle the broadcast intents that are sent by the Google Play application.
Making the request

You must specify four keys in the request Bundle. The following code sample shows how to set these keys and make a purchase request for a single in-app item. In the sample, mProductId is the Google Play product ID of an in-app item (which is listed in the application's product list), and mService is an instance of the MarketBillingService interface.

/**
* Request type is REQUEST_PURCHASE
*/
  Bundle request = makeRequestBundle("REQUEST_PURCHASE");
  request.putString(ITEM_ID, mProductId);
  // Request is for a standard in-app product
  request.putString(ITEM_TYPE, "inapp");
  // Note that the developer payload is optional.
  if (mDeveloperPayload != null) {
    request.putString(DEVELOPER_PAYLOAD, mDeveloperPayload);
  }
  Bundle response = mService.sendBillingRequest(request);
  // Do something with this response.

The makeRequestBundle() method constructs an initial Bundle, which contains the three keys that are required for all requests: BILLING_REQUEST, API_VERSION, and PACKAGE_NAME. The ITEM_ID key is then added to the Bundle prior to invoking the sendBillingRequest() method.

The request returns a synchronous Bundle response, which contains three keys: RESPONSE_CODE, PURCHASE_INTENT, and REQUEST_ID. The RESPONSE_CODE key provides you with the status of the request and the REQUEST_ID key provides you with a unique request identifier for the request. The PURCHASE_INTENT key provides you with a PendingIntent, which you can use to launch the checkout UI.

Using the pending intent

How you use the pending intent depends on which version of Android a device is running. On Android 1.6, you must use the pending intent to launch the checkout UI in its own separate task instead of your application's activity stack. On Android 2.0 and higher, you can use the pending intent to launch the checkout UI on your application's activity stack. The following code shows you how to do this. You can find this code in the PurchaseObserver.java file in the sample application.

void startBuyPageActivity(PendingIntent pendingIntent, Intent intent) {
  if (mStartIntentSender != null) {
    // This is on Android 2.0 and beyond.  The in-app checkout page activity
    // will be on the activity stack of the application.
    try {
      // This implements the method call:
      // mActivity.startIntentSender(pendingIntent.getIntentSender(),
      //     intent, 0, 0, 0);
      mStartIntentSenderArgs[0] = pendingIntent.getIntentSender();
      mStartIntentSenderArgs[1] = intent;
      mStartIntentSenderArgs[2] = Integer.valueOf(0);
      mStartIntentSenderArgs[3] = Integer.valueOf(0);
      mStartIntentSenderArgs[4] = Integer.valueOf(0);
      mStartIntentSender.invoke(mActivity, mStartIntentSenderArgs);
    } catch (Exception e) {
      Log.e(TAG, "error starting activity", e);
      }
  } else {
    // This is on Android 1.6. The in-app checkout page activity will be on its
    // own separate activity stack instead of on the activity stack of
    // the application.
    try {
      pendingIntent.send(mActivity, 0 /* code */, intent);
    } catch (CanceledException e) {
      Log.e(TAG, "error starting activity", e);
      }
  }
}

Important: You must launch the pending intent from an activity context and not an application context. Also, you cannot use the singleTop launch mode to launch the pending intent. If you do either of these, the Android system will not attach the pending intent to your application process. Instead, it will bring Google Play to the foreground, disrupting your application.

Handling broadcast intents

A REQUEST_PURCHASE request also triggers two asynchronous responses (broadcast intents). First, the Google Play application sends a RESPONSE_CODE broadcast intent, which provides error information about the request. If the request does not generate an error, the RESPONSE_CODE broadcast intent returns RESULT_OK, which indicates that the request was successfully sent. (To be clear, a RESULT_OK response does not indicate that the requested purchase was successful; it indicates that the request was sent successfully to Google Play.)

Next, when the requested transaction changes state (for example, the purchase is successfully charged to a credit card or the user cancels the purchase), the Google Play application sends an IN_APP_NOTIFY broadcast intent. This message contains a notification ID, which you can use to retrieve the transaction details for the REQUEST_PURCHASE request.

Note: The Google Play application also sends an IN_APP_NOTIFY for refunds. For more information, see Handling IN_APP_NOTIFY messages.

Because the purchase process is not instantaneous and can take several seconds (or more), you must assume that a purchase request is pending from the time you receive a RESULT_OK message until you receive an IN_APP_NOTIFY message for the transaction. While the transaction is pending, the Google Play checkout UI displays an "Authorizing purchase..." notification; however, this notification is dismissed after 60 seconds and you should not rely on this notification as your primary means of conveying transaction status to users. Instead, we recommend that you do the following:

  • Add an Activity to your application that shows users the status of pending and completed in-app purchases.
  • Use a status bar notification to keep users informed about the progress of a purchase.

To use these two UI elements, you could invoke a status bar notification with a ticker-text message that says "Purchase pending" when your application receives a RESULT_OK message. Then, when your application receives an IN_APP_NOTIFY message, you could update the notification with a new message that says "Purchase succeeded" or "Purchase failed." When a user touches the expanded status bar notification, you could launch the activity that shows the status of pending and completed in-app purchases.

If you use some other UI technique to inform users about the state of a pending transaction, be sure that your pending status UI does not block your application. For example, you should avoid using a hovering progress wheel to convey the status of a pending transaction because a pending transaction could last a long time, particularly if a device loses network connectivity and cannot receive transaction updates from Google Play.

Important: If a user purchases a managed item, you must prevent the user from purchasing the item again while the original transaction is pending. If a user attempts to purchase a managed item twice, and the first transaction is still pending, Google Play will display an error to the user; however, Google Play will not send an error to your application notifying you that the second purchase request was canceled. This might cause your application to get stuck in a pending state while it waits for an IN_APP_NOTIFY message for the second purchase request.

Retrieving transaction information for a purchase or refund (GET_PURCHASE_INFORMATION)

You retrieve transaction information in response to an IN_APP_NOTIFY broadcast intent. The IN_APP_NOTIFY message contains a notification ID, which you can use to retrieve transaction information.

To retrieve transaction information for a purchase or refund you must specify five keys in the request Bundle. The following code sample shows how to set these keys and make the request. In the sample, mService is an instance of the MarketBillingService interface.

/**
* Request type is GET_PURCHASE_INFORMATION
*/
  Bundle request = makeRequestBundle("GET_PURCHASE_INFORMATION");
  request.putLong(REQUEST_NONCE, mNonce);
  request.putStringArray(NOTIFY_IDS, mNotifyIds);
  Bundle response = mService.sendBillingRequest(request);
  // Do something with this response.
}

The makeRequestBundle() method constructs an initial Bundle, which contains the three keys that are required for all requests: BILLING_REQUEST, API_VERSION, and PACKAGE_NAME. The additional keys are then added to the bundle prior to invoking the sendBillingRequest() method. The REQUEST_NONCE key contains a cryptographically secure nonce (number used once) that you must generate. The Google Play application returns this nonce with the PURCHASE_STATE_CHANGED broadcast intent so you can verify the integrity of the transaction information. The NOTIFY_IDS key contains an array of notification IDs, which you received in the IN_APP_NOTIFY broadcast intent.

The request returns a synchronous Bundle response, which contains two keys: RESPONSE_CODE and REQUEST_ID. The RESPONSE_CODE key provides you with the status of the request and the REQUEST_ID key provides you with a unique request identifier for the request.

A GET_PURCHASE_INFORMATION request also triggers two asynchronous responses (broadcast intents). First, the Google Play application sends a RESPONSE_CODE broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Google Play application sends a PURCHASE_STATE_CHANGED broadcast intent. This message contains detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.

Acknowledging transaction information (CONFIRM_NOTIFICATIONS)

To acknowledge that you received transaction information you send a CONFIRM_NOTIFICATIONS request. You must specify four keys in the request Bundle. The following code sample shows how to set these keys and make the request. In the sample, mService is an instance of the MarketBillingService interface.

/**
* Request type is CONFIRM_NOTIFICATIONS
*/
  Bundle request = makeRequestBundle("CONFIRM_NOTIFICATIONS");
  request.putStringArray(NOTIFY_IDS, mNotifyIds);
  Bundle response = mService.sendBillingRequest(request);
  // Do something with this response.
}

The makeRequestBundle() method constructs an initial Bundle, which contains the three keys that are required for all requests: BILLING_REQUEST, API_VERSION, and PACKAGE_NAME. The additional NOTIFY_IDS key is then added to the bundle prior to invoking the sendBillingRequest() method. The NOTIFY_IDS key contains an array of notification IDs, which you received in an IN_APP_NOTIFY broadcast intent and also used in a GET_PURCHASE_INFORMATION request.

The request returns a synchronous Bundle response, which contains two keys: RESPONSE_CODE and REQUEST_ID. The RESPONSE_CODE key provides you with the status of the request and the REQUEST_ID key provides you with a unique request identifier for the request.

A CONFIRM_NOTIFICATIONS request triggers a single asynchronous response—a RESPONSE_CODE broadcast intent. This broadcast intent provides status and error information about the request.

You must send a confirmation when you receive transaction information from Google Play. If you don't send a confirmation message, Google Play will continue sending IN_APP_NOTIFY messages for the transactions you have not confirmed. Also, your application must be able to handle IN_APP_NOTIFY messages that contain multiple orders.

In addition, as a best practice, you should not send a CONFIRM_NOTIFICATIONS request for a purchased item until you have delivered the item to the user. This way, if your application crashes or something else prevents your application from delivering the product, your application will still receive an IN_APP_NOTIFY broadcast intent from Google Play indicating that you need to deliver the product.

Restoring transaction information (RESTORE_TRANSACTIONS)

To restore a user's transaction information, you send a RESTORE_TRANSACTIONS request. You must specify four keys in the request Bundle. The following code sample shows how to set these keys and make the request. In the sample, mService is an instance of the MarketBillingService interface.

/**
* Request type is RESTORE_TRANSACTIONS
*/
  Bundle request = makeRequestBundle("RESTORE_TRANSACTIONS");
  request.putLong(REQUEST_NONCE, mNonce);
  Bundle response = mService.sendBillingRequest(request);
  // Do something with this response.
}

The makeRequestBundle() method constructs an initial Bundle, which contains the three keys that are required for all requests: BILLING_REQUEST, API_VERSION, and PACKAGE_NAME. The additional REQUEST_NONCE key is then added to the bundle prior to invoking the sendBillingRequest() method. The REQUEST_NONCE key contains a cryptographically secure nonce (number used once) that you must generate. The Google Play application returns this nonce with the transactions information contained in the PURCHASE_STATE_CHANGED broadcast intent so you can verify the integrity of the transaction information.

The request returns a synchronous Bundle response, which contains two keys: RESPONSE_CODE and REQUEST_ID. The RESPONSE_CODE key provides you with the status of the request and the REQUEST_ID key provides you with a unique request identifier for the request.

A RESTORE_TRANSACTIONS request also triggers two asynchronous responses (broadcast intents). First, the Google Play application sends a RESPONSE_CODE broadcast intent, which provides status and error information about the request. Next, if the request was successful, the Google Play application sends a PURCHASE_STATE_CHANGED broadcast intent. This message contains the detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). The message includes the signature so you can verify the integrity of the signed string.

Note: You should use the RESTORE_TRANSACTIONS request type only when your application is installed for the first time on a device or when your application has been removed from a device and reinstalled.

Other service tasks

You may also want your Service to receive intent messages from your BroadcastReceiver. You can use these intent messages to convey the information that was sent asynchronously from the Google Play application to your BroadcastReceiver. To see an example of how you can send and receive these intent messages, see the BillingReceiver.java and BillingService.java files in the sample application. You can use these samples as a basis for your own implementation. However, if you use any of the code from the sample application, be sure you follow the guidelines in Security and Design.

Creating a BroadcastReceiver

The Google Play application uses broadcast intents to send asynchronous billing responses to your application. To receive these intent messages, you need to create a BroadcastReceiver that can handle the following intents:

  • com.android.vending.billing.RESPONSE_CODE

    This broadcast intent contains a Google Play response code, and is sent after you make an in-app billing request. For more information about the response codes that are sent with this response, see Google Play Response Codes for In-app Billing.

  • com.android.vending.billing.IN_APP_NOTIFY

    This response indicates that a purchase has changed state, which means a purchase succeeded, was canceled, or was refunded. For more information about notification messages, see In-app Billing Broadcast Intents

  • com.android.vending.billing.PURCHASE_STATE_CHANGED

    This broadcast intent contains detailed information about one or more transactions. For more information about purchase state messages, see In-app Billing Broadcast Intents

Each of these broadcast intents provide intent extras, which your BroadcastReceiver must handle. The intent extras are listed in the following table (see table 1).

Table 1. Description of broadcast intent extras that are sent in response to billing requests.

Intent Extra Description
com.android.vending.billing.RESPONSE_CODE request_id A long representing a request ID. A request ID identifies a specific billing request and is returned by Google Play at the time a request is made.
com.android.vending.billing.RESPONSE_CODE response_code An int representing the actual Google Play server response code.
com.android.vending.billing.IN_APP_NOTIFY notification_id A String representing the notification ID for a given purchase state change. Google Play notifies you when there is a purchase state change and the notification includes a unique notification ID. To get the details of the purchase state change, you send the notification ID with the GET_PURCHASE_INFORMATION request.
com.android.vending.billing.PURCHASE_STATE_CHANGED inapp_signed_data A String representing the signed JSON string. The JSON string contains information about the billing transaction, such as order number, amount, and the item that was purchased or refunded.
com.android.vending.billing.PURCHASE_STATE_CHANGED inapp_signature A String representing the signature of the JSON string.

The following code sample shows how to handle these broadcast intents and intent extras within a BroadcastReceiver. The BroadcastReceiver in this case is named BillingReceiver, just as it is in the sample application.

public class BillingReceiver extends BroadcastReceiver {

  private static final String TAG = "BillingReceiver";

  // Intent actions that we receive in the BillingReceiver from Google Play.
  // These are defined by Google Play and cannot be changed.
  // The sample application defines these in the Consts.java file.
  public static final String ACTION_NOTIFY =
      "com.android.vending.billing.IN_APP_NOTIFY";
  public static final String ACTION_RESPONSE_CODE =
      "com.android.vending.billing.RESPONSE_CODE";
  public static final String ACTION_PURCHASE_STATE_CHANGED =
      "com.android.vending.billing.PURCHASE_STATE_CHANGED";

  // The intent extras that are passed in an intent from Google Play.
  // These are defined by Google Play and cannot be changed.
  // The sample application defines these in the Consts.java file.
  public static final String NOTIFICATION_ID = "notification_id";
  public static final String INAPP_SIGNED_DATA = "inapp_signed_data";
  public static final String INAPP_SIGNATURE = "inapp_signature";
  public static final String INAPP_REQUEST_ID = "request_id";
  public static final String INAPP_RESPONSE_CODE = "response_code";


  @Override
  public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
      String signedData = intent.getStringExtra(INAPP_SIGNED_DATA);
      String signature = intent.getStringExtra(INAPP_SIGNATURE);
      // Do something with the signedData and the signature.
    } else if (ACTION_NOTIFY.equals(action)) {
      String notifyId = intent.getStringExtra(NOTIFICATION_ID);
      // Do something with the notifyId.
    } else if (ACTION_RESPONSE_CODE.equals(action)) {
      long requestId = intent.getLongExtra(INAPP_REQUEST_ID, -1);
      int responseCodeIndex = intent.getIntExtra(INAPP_RESPONSE_CODE,
        ResponseCode.RESULT_ERROR.ordinal());
      // Do something with the requestId and the responseCodeIndex.
    } else {
      Log.w(TAG, "unexpected action: " + action);
    }
  }
  // Perform other processing here, such as forwarding intent messages
  // to your local service.
}

In addition to receiving broadcast intents from the Google Play application, your BroadcastReceiver must handle the information it received in the broadcast intents. Usually, your BroadcastReceiver does this by sending the information to a local service (discussed in the next section). The BillingReceiver.java file in the sample application shows you how to do this. You can use this sample as a basis for your own BroadcastReceiver. However, if you use any of the code from the sample application, be sure you follow the guidelines that are discussed in Security and Design .

Securing Your Application

To help ensure the integrity of the transaction information that is sent to your application, Google Play signs the JSON string that is contained in the PURCHASE_STATE_CHANGED broadcast intent. Google Play uses the private key that is associated with your publisher account to create this signature. The Developer Console generates an RSA key pair for each publisher account. You can find the public key portion of this key pair on your account's profile page. It is the same public key that is used with Google Play licensing.

When Google Play signs a billing response, it includes the signed JSON string (unencrypted) and the signature. 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 help detect responses that have been tampered with or that have been spoofed. You can perform this signature verification step in your application; however, if your application connects to a secure remote server then we recommend that you perform the signature verification on that server.

In-app billing also uses nonces (a random number used once) to help verify the integrity of the purchase information that's returned from Google Play. Your application must generate a nonce and send it with a GET_PURCHASE_INFORMATION request and a RESTORE_TRANSACTIONS request. When Google Play receives the request, it adds the nonce to the JSON string that contains the transaction information. The JSON string is then signed and returned to your application. When your application receives the JSON string, you need to verify the nonce as well as the signature of the JSON string.

For more information about best practices for security and design, see Security and Design.

Verifying signatures and nonces

Google Play's in-app billing service uses two mechanisms to help verify the integrity of the transaction information you receive from Google Play: nonces and signatures. A nonce (number used once) is a cryptographically secure number that your application generates and sends with every GET_PURCHASE_INFORMATION and RESTORE_TRANSACTIONS request. The nonce is returned with the PURCHASE_STATE_CHANGED broadcast intent, enabling you to verify that any given PURCHASE_STATE_CHANGED response corresponds to an actual request that you made. Every PURCHASE_STATE_CHANGED broadcast intent also includes a signed JSON string and a signature, which you can use to verify the integrity of the response.

Your application must provide a way to generate, manage, and verify nonces. The following sample code shows some simple methods you can use to do this.

  private static final SecureRandom RANDOM = new SecureRandom();
  private static HashSet<Long> sKnownNonces = new HashSet<Long>();

  public static long generateNonce() {
    long nonce = RANDOM.nextLong();
    sKnownNonces.add(nonce);
    return nonce;
  }

  public static void removeNonce(long nonce) {
    sKnownNonces.remove(nonce);
  }

  public static boolean isNonceKnown(long nonce) {
    return sKnownNonces.contains(nonce);
  }

Your application must also provide a way to verify the signatures that accompany every PURCHASE_STATE_CHANGED broadcast intent. The Security.java file in the sample application shows you how to do this. If you use this file as a basis for your own security implementation, be sure to follow the guidelines in Security and Design and obfuscate your code.

You will need to use your Google Play public key to perform the signature verification. The following procedure shows you how to retrieve Base64-encoded public key from the Google Play Developer Console.

  1. Log in to your publisher account.
  2. On the upper left part of the page, click All applications and then click the app name in the listing.
  3. Click Services & APIs and find "Your License Key for this Application" on the page.
  4. Copy the app's public key.

Important: To keep your public key safe from malicious users and hackers, do not embed your public key as an entire literal string. Instead, construct the string at runtime from pieces or use bit manipulation (for example, XOR with some other string) to hide the actual key. The key itself is not secret information, but you do not want to make it easy for a hacker or malicious user to replace the public key with another key.

Figure 2. An app's license key is available from the Services & APIs page in the Developer Console.

Modifying Your Application Code

After you finish adding in-app billing components to your project, you are ready to modify your application's code. For a typical implementation, like the one that is demonstrated in the sample application, this means you need to write code to do the following:

  • Create a storage mechanism for storing users' purchase information.
  • Create a user interface that lets users select items for purchase.

The sample code in Dungeons.java shows you how to do both of these tasks.

Creating a storage mechanism for storing purchase information

You must set up a database or some other mechanism for storing users' purchase information. The sample application provides an example database (PurchaseDatabase.java); however, the example database has been simplified for clarity and does not exhibit the security best practices that we recommend. If you have a remote server, we recommend that you store purchase information on your server instead of in a local database on a device. For more information about security best practices, see Security and Design.

Note: If you store any purchase information on a device, be sure to encrypt the data and use a device-specific encryption key. Also, if the purchase type for any of your items is "unmanaged," we recommend that you back up the purchase information for these items to a remote server or use Android's data backup framework to back up the purchase information. Backing up purchase information for unmanaged items is important because unmanaged items cannot be restored by using the RESTORE_TRANSACTIONS request type.

Creating a user interface for selecting items

You must provide users with a means for selecting items that they want to purchase. Google Play provides the checkout user interface (which is where the user provides a form of payment and approves the purchase), but your application must provide a control (widget) that invokes the sendBillingRequest() method when a user selects an item for purchase.

You can render the control and trigger the sendBillingRequest() method any way you want. The sample application uses a spinner widget and a button to present items to a user and trigger a billing request (see Dungeons.java). The user interface also shows a list of recently purchased items.