| page.title=Implementing Subscriptions <span style="font-size:16px;">(IAB Version 2)</span> |
| @jd:body |
| |
| <div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div> |
| <div id="qv-wrapper" style="margin-top:0;"> |
| <div id="qv"> |
| <h2>In this document</h2> |
| <ol> |
| <li><a href="#sample">Sample Application</a></li> |
| <li><a href="#model">Application Model</a></li> |
| <li><a href="#token">Purchase Token</a></li> |
| <li><a href="#version">Checking the In-app Billing API Version</a></li> |
| <li><a href="purchase">Purchasing a Subscription</a></li> |
| <li><a href="#restore">Restoring Transactions</a></li> |
| <li><a href="#validity">Checking Subscription Validity</a></li> |
| <li><a href="#viewstatus">Letting Users Cancel or View Status</a></li> |
| <li><a href="#purchase-state-changes">Recurring Billing and Changes in Purchase State</a></li> |
| <li><a href="modifying">Modifying Your App for Subscriptions</a></li> |
| </ol> |
| </div> |
| </div> |
| |
| <p>This document is focused on highlighting implementation details that are |
| specific to subscriptions with the Version 2 API. To understand how |
| subscriptions work, see <a href="{@docRoot}google/play/billing/billing_subscriptions.html">In-app Billing Subscriptions</a>.</p> |
| |
| |
| <h2 id="sample">Sample Application</h2> |
| |
| <p>To help you get started with your In-app Billing implementation and |
| subscriptions, an updated Version of the In-app Billing sample app is available. |
| You can download the sample app from the Android SDK repository using the |
| Android SDK Manager. For details, see <a |
| href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download"> |
| Downloading the Sample Application</a>.</p> |
| |
| <h2 id="model">Application Model</h2> |
| |
| <p>With subscriptions, your app uses the standard In-app Billing application |
| model, sending billing requests to the Play Store application over interprocess |
| communication (IPC) and receiving purchase responses from the Play Store app in |
| the form of asynchronous broadcast intents. Your application does not manage any |
| network connections between itself and the Google Play server or use any special |
| APIs from the Android platform.</p> |
| |
| <p>Your app also uses the standard In-app Billing components — a billing |
| Service for sending requests, a BroadcastReceiver for receiving the responses, |
| and a security component for verifying that the response was sent by Google |
| Play. Also recommended are a response Handler for processing notifications, |
| errors, and status messages, and an observer for sending callbacks to your |
| application as needed. All of these components and their interactions are |
| described in full in the <a |
| href="{@docRoot}google/play/billing/v2/api.html">In-app Billing |
| Overview</a> and related documents.</p> |
| |
| <p>To initiate different types of billing communication with Google Play, your |
| app will use the standard set of in-app billing requests and receive the same |
| responses. Inside the requests and responses are two new fields described below. |
| </p> |
| |
| <h2 id="token">Purchase Token</h2> |
| |
| <p>Central to the end-to-end architecture for subscriptions is the purchase |
| token, a string value that uniquely identifies (and associates) a user ID and a |
| subscription ID. Google Play generates the purchase token when the user |
| completes the purchase of a subscription product (and payment is approved by |
| Google Checkout) and then sends it to the purchasing app on the device through the |
| In-app Billing API. </p> |
| |
| <p>At the conclusion of a <code>PURCHASE_REQUEST</code> message flow, your app |
| can retrieve the purchase token and other transaction details by initiating a |
| <code>GET_PURCHASE_INFORMATION</code> request. The Bundle returned by the call |
| contains an JSON array of order objects. In the order corresponding to the |
| subscription purchase, the token is available in the <code>purchaseToken</code> |
| field. </p> |
| |
| <p>An example of a JSON order object that includes a subscription purchase token |
| is shown below. </p> |
| |
| <pre class="no-pretty-print" style="color:black">{ "nonce" : 1836535032137741465, |
| "orders" : |
| [{ "notificationId" : "android.test.purchased", |
| "orderId" : "12999556515565155651.5565135565155651" |
| "packageName" : "com.example.dungeons", |
| "productId" : "android.test.purchased", |
| "developerPayload" : "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ", |
| "purchaseTime" : 1290114783411, |
| "purchaseState" : 0, |
| "purchaseToken" : "rojeslcdyyiapnqcynkjyyjh" }] |
| } |
| </pre> |
| |
| <p>After receiving a purchase token, your apps can store the token locally or |
| pass it to your backend servers, which can then use it to query the billing |
| status or cancel the subscription remotely. If your app will store the token |
| locally, please read the <a |
| href="{@docRoot}google/play/billing/billing_best_practices.html">Security and |
| Design</a> document for best practices for maintaining the security of your |
| data.</p> |
| |
| <h2 id="version">Checking the In-app Billing API Version</h2> |
| |
| <p>Subscriptions support is available only in versions of Google Play that |
| support the In-app Billing v2 API (Google Play 3.5 and higher). For your app, |
| an essential first step at launch is to check whether the Version of Google Play |
| installed on the device supports the In-app Billing v2 API and |
| subscriptions.</p> |
| |
| <p>To do this, create a CHECK_BILLING_SUPPORTED request Bundle that includes the |
| required key-value pairs, together with</p> |
| |
| <ul> |
| <li>The <code>API_VERSION</code> key, assigning a value of 2.</li> |
| <li>The <code>BILLING_REQUEST_ITEM_TYPE</code> key, assigning a value of “subs”</li> |
| </ul> |
| |
| <p>Send the request using <code>sendBillingRequest(Bundle)</code> and receive |
| the response Bundle. You can extract the response from the |
| <code>BILLING_RESPONSE_RESPONSE_CODE</code> key of the response. RESULT_OK |
| indicates that subscriptions are supported.</p> |
| |
| <p>The sample app declares constants for the accepted |
| <code>BILLING_REQUEST_ITEM_TYPE</code> values (from Consts.java):</p> |
| |
| <pre class="pretty-print"> // These are the types supported in the IAB v2 |
| public static final String ITEM_TYPE_INAPP = "inapp"; |
| public static final String ITEM_TYPE_SUBSCRIPTION = "subs"; |
| </pre> |
| |
| <p>It sets up a convenience method for building the request bundle (from BillingService.java):</p> |
| |
| <pre class="pretty-print"> protected Bundle makeRequestBundle(String method) { |
| Bundle request = new Bundle(); |
| request.putString(Consts.BILLING_REQUEST_METHOD, method); |
| request.putInt(Consts.BILLING_REQUEST_<code>API_VERSION</code>, 2); |
| request.putString(Consts.BILLING_REQUEST_PACKAGE_NAME, getPackageName()); |
| return request; |
| } |
| </pre> |
| |
| <p>Here’s an example of how to test support for In-App Billing v2 and subscriptions |
| (from BillingService.java):</p> |
| |
| <pre class="pretty-print"> /** |
| * Wrapper class that checks if in-app billing is supported. |
| */ |
| class CheckBillingSupported extends BillingRequest { |
| public String mProductType = null; |
| public CheckBillingSupported() { |
| // This object is never created as a side effect of starting this |
| // service so we pass -1 as the startId to indicate that we should |
| // not stop this service after executing this request. |
| super(-1); |
| } |
| |
| public CheckBillingSupported(String type) { |
| super(-1); |
| mProductType = type; |
| } |
| |
| @Override |
| protected long run() throws RemoteException { |
| Bundle request = makeRequestBundle("CHECK_BILLING_SUPPORTED"); |
| if (mProductType != null) { |
| request.putString(Consts.<code>BILLING_REQUEST_ITEM_TYPE</code>, mProductType); |
| } |
| Bundle response = mService.sendBillingRequest(request); |
| int responseCode = response.getInt(Consts.<code>BILLING_RESPONSE_RESPONSE_CODE</code>); |
| if (Consts.DEBUG) { |
| Log.i(TAG, "CheckBillingSupported response code: " + |
| ResponseCode.valueOf(responseCode)); |
| } |
| boolean billingSupported = (responseCode == ResponseCode.RESULT_OK.ordinal()); |
| ResponseHandler.checkBillingSupportedResponse(billingSupported, mProductType); |
| return Consts.BILLING_RESPONSE_INVALID_REQUEST_ID; |
| } |
| } |
| </pre> |
| |
| <h2 id="purchase">Requesting a Subscription Purchase</h2> |
| |
| <p>Once you’ve checked the API Version as described above and determined that |
| subscriptions are supported, you can present subscription products to the user |
| for purchase. When the user has selected a subscription product and initiated a |
| purchase, your app handles the purchase just as it would for other in-app |
| products — by sending a REQUEST_PURCHASE request. You can then launch |
| Google Play to display the checkout user interface and handle the financial |
| transaction.. |
| |
| <p>The REQUEST_PURCHASE includes a Bundle containing the item details, as |
| described in the <a |
| href="{@docRoot}google/play/billing/v2/api.html">In-app Billing |
| Overview</a>. For a subscription, the Bundle must also specify:</p> |
| |
| <ul> |
| <li>The <code>ITEM_ID</code> key, with a value that specifies a valid, published |
| subscription product.</li> |
| <li>The <code>ITEM_TYPE</code> key, with a value of “subs” |
| (<code>ITEM_TYPE_SUBSCRIPTION</code> in the sample app). If the request does not |
| specify the subscription's <code>ITEM_TYPE</code>, Google Play attempts to |
| handle the request as a standard in-app purchase (one-time purchase).</li> |
| </ul> |
| |
| <p>Google Play synchronously returns a response bundle that includes |
| <code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</code>, and |
| <code>REQUEST_ID</code>. Your app uses the <code>PURCHASE_INTENT</code> to |
| launch the checkout UI and the message flow proceeds exactly as described in <a |
| href="{@docRoot}google/play/billing/v2/api.html#billing-message- |
| sequence">Messaging sequence</a>.</p> |
| |
| <p>Here’s how the sample app initiates a purchase for a subscription, where |
| <code>mProductType</code> is <code>ITEM_TYPE_SUBSCRIPTION</code> (from |
| BillingService.java).</p> |
| |
| <pre class="pretty-print"> /** |
| * Wrapper class that requests a purchase. |
| */ |
| class RequestPurchase extends BillingRequest { |
| public final String mProductId; |
| public final String mDeveloperPayload; |
| public final String mProductType; |
| |
| . . . |
| |
| @Override |
| protected long run() throws RemoteException { |
| Bundle request = makeRequestBundle("REQUEST_PURCHASE"); |
| request.putString(Consts.BILLING_REQUEST_ITEM_ID, mProductId); |
| request.putString(Consts.<code>BILLING_REQUEST_ITEM_TYPE</code>, mProductType); |
| // Note that the developer payload is optional. |
| if (mDeveloperPayload != null) { |
| request.putString(Consts.BILLING_REQUEST_DEVELOPER_PAYLOAD, mDeveloperPayload); |
| } |
| Bundle response = mService.sendBillingRequest(request); |
| PendingIntent pendingIntent |
| = response.getParcelable(Consts.BILLING_RESPONSE_PURCHASE_INTENT); |
| if (pendingIntent == null) { |
| Log.e(TAG, "Error with requestPurchase"); |
| return Consts.BILLING_RESPONSE_INVALID_REQUEST_ID; |
| } |
| |
| Intent intent = new Intent(); |
| ResponseHandler.buyPageIntentResponse(pendingIntent, intent); |
| return response.getLong(Consts.BILLING_RESPONSE_REQUEST_ID, |
| Consts.BILLING_RESPONSE_INVALID_REQUEST_ID); |
| } |
| |
| @Override |
| protected void responseCodeReceived(ResponseCode responseCode) { |
| ResponseHandler.responseCodeReceived(BillingService.this, this, responseCode); |
| } |
| } |
| </pre> |
| |
| <h2 id="restoring">Restoring Transactions</h2> |
| |
| <p>Subscriptions always use the <em>managed by user account</em> purchase type, |
| so that you can restore a record of subscription transactions on the device when |
| needed. When a user installs your app onto a new device, or when the user |
| uninstalls/reinstalls the app on the original device, your app should restore |
| the subscriptions that the user has purchased.</p> |
| |
| <p>The process for restoring subscriptions transactions is the same as described |
| in <a |
| href="{@docRoot}google/play/billing/v2/api.html#billing-message- |
| sequence">Messaging sequence</a>. Your app sends a |
| <code>RESTORE_TRANSACTIONS</code> request to Google Play. Google Play sends two |
| broadcast intents as asynchronous responses — a <code>RESPONSE_CODE</code> |
| intent and a <code>PURCHASE_STATE_CHANGED</code> intent.</p> |
| |
| <p>The <code>PURCHASE_STATE_CHANGED</code> intent contains a notification ID |
| that your app can use to retrieve the purchase details, including the purchase |
| token, by sending a standard <code>GET_PURCHASE_INFORMATION</code> request. The |
| <code>Bundle</code> returned in the call includes an JSON array of order objects |
| corresponding to subscription (and in-app product) purchases that you can |
| restore locally.</p> |
| |
| <p>Your app can store the restored purchase state and other transaction details |
| in the way that best meets your needs. Your app can use it later to check the |
| subscription validity, although please read the <a |
| href="{@docRoot}google/play/billing/billing_best_practices.html">Security and |
| Design</a> document for best practices for maintaining the security of your |
| data.</p> |
| |
| <h2 id="validity">Checking Subscription Validity</h2> |
| |
| <p>Subscriptions are time-bound purchases that require successful billing |
| recurrences over time to remain valid. Your app should check the validity of |
| purchased subscriptions at launch or prior to granting access to subscriber |
| content.</p> |
| |
| <p>With In-app Billing, you validate a subscription by keeping track of its |
| purchase state and then checking the state whenever needed. Google Play |
| provides two ways to let you know when the purchase |
| state of a subscription changes:</p> |
| |
| <ul> |
| <li><em>In-app Billing Notifications</em>. Google Play pushes a notification |
| to your app to indicate a change in the purchase state of a subscription. Your app can |
| store the most recent purchase state for a given purchase token and then check |
| that state at run time, as needed.</li> |
| <li><em>Google Play Android Developer API</em>. You can use this HTTP-based |
| API to poll Google Play for the current purchase state of a subscription. You |
| can store the purchased state for each <code>purchaseToken</code> on your |
| backend servers. For more information, see <a href="#play-dev-api">Google Play |
| Android Developer API</a>, below.</li> |
| </ul> |
| |
| <p>For most use-cases, especially those where backend servers are already keeping |
| track of subscribed users, implementing a combination of both methods is the |
| recommended approach. A typical implementation might work like this:</p> |
| |
| <ul> |
| <li>When the user successfully purchases a new subscription, your app notifies a |
| backend server, which stores the purchase token, user name, and other |
| information in a secure location.</li> |
| <li>Since your app cannot know the expiration date, your server can poll Google |
| Play to get the expiration and store it with the purchase token and other |
| data.</li> |
| <li>Because your server now knows the expiration date, it does not need to poll |
| Google Play again until after the expiration date, at which time it can confirm |
| that the subscription was not cancelled.</li> |
| <li>On the client side, your app can continue to update the server whenever the |
| purchase state changes, storing the state locally.</li> |
| </ul> |
| |
| <p>If you are using both notifications and the Google Play Android Developer API to validate subscriptions, we recommend the following:</p> |
| |
| <ul> |
| <li>If your app wants to check validity but you can’t reach your server (or |
| you don’t have a server), use the latest purchase state received by |
| notification.</li> |
| <li>If you have a server and it’s reachable, always give preference to the |
| purchase state obtained from your server over the state received in |
| notifications.</li> |
| </ul> |
| |
| <p>If necessary, you can also use a <code>RESTORE_TRANSACTIONS</code> request to retrieve a record of all managed and in-app products purchased by the user, which you can then store locally. However, using <code>RESTORE_TRANSACTIONS</code> on a regular basis is not recommended because of performance impacts.</p> |
| |
| <p>Regardless of the approach you choose, your app should check subscriptions |
| and validity at launch, such as prior to accessing subscriber content, game |
| levels, and so on.</p> |
| |
| <p class="table-caption"><strong>Table 1.</strong> Summary of purchaseState |
| values for subscription purchases, as received with a |
| <code>PURCHASE_STATE_CHANGED</code> intent.</p> |
| |
| <table> |
| <tr> |
| <th>State</th><th>purchaseState Value</th><th>Comments</th> |
| </tr> |
| <tr> |
| <td>Purchased successfully</td><td><code>0</code></td><td>Sent at original purchase only (not at recurring billing cycles).</td></tr> |
| <td>Cancelled</td><td><code>1</code></td><td>Sent at original purchase only if the purchase has failed for some reason. </td></tr> |
| <td>Refunded</td><td><code>2</code></td><td>The purchase was refunded.</code></td></tr> |
| <td>Subscription expired</td><td><code>3</code></td><td>Sent at the end of a billing cycle to indicate that the subscription expired without renewal because of non-payment or user-cancellation. Your app does not need to grant continued access to the subscription content. |
| </td></tr> |
| </table> |
| |
| |
| <h2 id="viewstatus">Letting the User Cancel or View Subscriptions</h2> |
| |
| <p>In-app Billing does not currently provide an API to let users directly view or cancel |
| subscriptions from within the purchasing app. Instead, users can launch the Play |
| Store app on their devices and go to the My Apps screen to manage subscriptions. In My Apps, |
| users can see a list of their subscriptions organized by application. Tapping one of the |
| subscriptions loads the app's product page, from which users can see active subscriptions |
| and billing status and cancel subscriptions as needed.</p> |
| |
| <p>To make it easier for users to find and manage their subscriptions from inside your app, |
| we recommend that you offer a "View My Subscriptions" or "Manage Subscriptions" option in |
| your UI that directly loads your app's product page in the Play Store app.</p> |
| |
| <p>To do this, create an intent with the <a |
| href="{@docRoot}reference/android/content/Intent.html#ACTION_VIEW">ACTION_VIEW</a> |
| action and include the <code>market://</code> URI (rather than the <code>http://</code> |
| URI) of your app's details page. Here’s an example:</p> |
| |
| <pre style="pretty-print">Intent intent = new Intent(Intent.ACTION_VIEW); |
| intent.setData(Uri.parse("market://details?id=com.example.app")); |
| startActivity(intent);</pre> |
| |
| <p>For more information, see |
| <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a>.</p> |
| |
| <h2 id="purchase-state-changes">Recurring Billing, Cancellation, and Changes In Purchase State</h2> |
| |
| <p>Google Play notifies your app when the user completes the purchase of a |
| subscription, but the purchase state does not change over time, provided that |
| recurring billing takes place successfully. Google Play does not notify your app |
| of a purchase state change <em>until the subscription expires because of |
| non-payment or user cancellation</em>. </p> |
| |
| <p>Over the life of a subscription, your app does not need to initiate any |
| recurring billing events — those are all handled by Google Play and they |
| are transparent to your application if billing is successful.</p> |
| |
| <p>When the user cancels a subscription during an active billing cycle, Google |
| Play <em>does not</em> notify your app immediately of the change in purchase |
| state. Instead, it waits until the end of the active billing cycle and then |
| notifies your app that the purchase state has changed to "Expired". </p> |
| |
| <p>Similarly, if payment for the next billing cycle fails, Google Play waits |
| until the end of the active billing cycle and then notifies your app at that time that the |
| purchase state has changed to "Expired".</p> |
| |
| <p>Your app can handle user cancellation and non-payment in the same way, since both cause |
| a change to the same "Expired" purchase state. Once the purchase state has become "Expired", |
| your app does not need to grant further access to the subscription content.</p> |
| |
| <h2 id="modifying">Modifying Your App for Subscriptions</h2> |
| |
| <p>For subscriptions, you make the same types of modifications to your app as |
| are described in <a |
| href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-implement"> |
| Modifying your Application Code</a>.</p> |
| |
| <p>Note that, in your UI that lets users view and select subscriptions for |
| purchase, you should add logic to check for purchased subscriptions and validate |
| them. Your UI should not present subscriptions if the user has already purchased |
| them.</p> |
| |
| |
| |
| |
| |