• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Implementing Subscriptions  <span style="font-size:16px;">(IAB Version 2)</span>
2excludeFromSuggestions=true
3@jd:body
4
5<p class="caution" style=
6"background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">
7  The <strong>In-app Billing Version 2 API</strong> has been deprecated in
8  favor of the Version 3 API. If your app is using In-app Billing, please
9  <strong>make sure that it is using the Version 3 API</strong>. If your app is
10  still using the Version 2 API, you must <strong>migrate to the Version 3 API
11  as soon as possible</strong>.<br>
12  <br>
13  We plan to turn off the In-app Billing Version 2 service on <strong>January
14  27, 2015</strong>, after which time users will <strong>no longer be able to
15  purchase in-app items and subscriptions through the Version 2 API</strong>.
16  We strongly encourage and recommend you migrate your apps to use Version 3
17  API by November 2014, to provide ample time for users to update their apps to
18  the new version.<br>
19  <br>
20  For more information, please see the <a href=
21  "http://support.google.com/googleplay/android-developer/answer/6090268">Help Center
22  article</a>. For common questions about transitioning your implementation to
23  In-app Billing Version 3, please see <a href=
24  "{@docRoot}google/play/billing/billing_overview.html#migration">Migration
25  Considerations</a>.
26</p>
27    <div id="qv-wrapper" style="margin-top:0;">
28<div id="qv">
29  <h2>In this document</h2>
30  <ol>
31        <li><a href="#sample">Sample Application</a></li>
32        <li><a href="#model">Application Model</a></li>
33        <li><a href="#token">Purchase Token</a></li>
34        <li><a href="#version">Checking the In-app Billing API Version</a></li>
35        <li><a href="#purchase">Purchasing a Subscription</a></li>
36        <li><a href="#restore">Restoring Transactions</a></li>
37        <li><a href="#validity">Checking Subscription Validity</a></li>
38        <li><a href="#viewstatus">Letting Users Cancel or View Status</a></li>
39        <li><a href="#purchase-state-changes">Recurring Billing and Changes in Purchase State</a></li>
40        <li><a href="#modifying">Modifying Your App for Subscriptions</a></li>
41   </ol>
42</div>
43</div>
44
45<p>This document is focused on highlighting implementation details that are
46specific to subscriptions with the Version 2 API. To understand how
47subscriptions work, see <a href="{@docRoot}google/play/billing/billing_subscriptions.html">In-app Billing Subscriptions</a>.</p>
48
49
50<h2 id="sample">Sample Application</h2>
51
52<p>To help you get started with your In-app Billing implementation and
53subscriptions, an updated Version of the In-app Billing sample app is available.
54You can download the sample app from the Android SDK repository using the
55Android SDK Manager. For details, see <a
56href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download">
57Downloading the Sample Application</a>.</p>
58
59<h2 id="model">Application Model</h2>
60
61<p>With subscriptions, your app uses the standard In-app Billing application
62model, sending billing requests to the Play Store application over interprocess
63communication (IPC) and receiving purchase responses from the Play Store app in
64the form of asynchronous broadcast intents. Your application does not manage any
65network connections between itself and the Google Play server or use any special
66APIs from the Android platform.</p>
67
68<p>Your app also uses the standard In-app Billing components &mdash; a billing
69Service for sending requests, a BroadcastReceiver for receiving the responses,
70and a security component for verifying that the response was sent by Google
71Play. Also recommended are a response Handler for processing notifications,
72errors, and status messages, and an observer for sending callbacks to your
73application as needed. All of these components and their interactions are
74described in full in the <a
75href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
76Overview</a> and related documents.</p>
77
78<p>To initiate different types of billing communication with Google Play, your
79app will use the standard set of in-app billing requests and receive the same
80responses. Inside the requests and responses are two new fields described below.
81</p>
82
83<h2 id="token">Purchase Token</h2>
84
85<p>Central to the end-to-end architecture for subscriptions is the purchase
86token, a string value that uniquely identifies (and associates) a user ID and a
87subscription ID. Google Play generates the purchase token when the user
88completes the purchase of a subscription product (and payment is approved by
89Google Wallet) and then sends it to the purchasing app on the device through the
90In-app Billing API. </p>
91
92<p>At the conclusion of a <code>PURCHASE_REQUEST</code> message flow, your app
93can retrieve the purchase token and other transaction details by initiating a
94<code>GET_PURCHASE_INFORMATION</code> request. The Bundle returned by the call
95contains an JSON array of order objects. In the order corresponding to the
96subscription purchase, the token is available in the <code>purchaseToken</code>
97field. </p>
98
99<p>An example of a JSON order object that includes a subscription purchase token
100is shown below. </p>
101
102<pre class="no-pretty-print" style="color:black">{ "nonce" : 1836535032137741465,
103  "orders" :
104    [{ "notificationId" : "android.test.purchased",
105       "orderId" : "12999556515565155651.5565135565155651"
106       "packageName" : "com.example.dungeons",
107       "productId" : "android.test.purchased",
108       "developerPayload" : "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
109       "purchaseTime" : 1290114783411,
110       "purchaseState" : 0,
111       "purchaseToken" : "rojeslcdyyiapnqcynkjyyjh" }]
112}
113</pre>
114
115<p>After receiving a purchase token, your apps can store the token locally or
116pass it to your backend servers, which can then use it to query the billing
117status or cancel the subscription remotely. If your app will store the token
118locally, please read the <a
119href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
120Design</a> document for best practices for maintaining the security of your
121data.</p>
122
123<h2 id="version">Checking the In-app Billing API Version</h2>
124
125<p>Subscriptions support is available only in versions of Google Play that
126support the In-app Billing v2 API (Google Play 3.5 and higher). For your app,
127an essential first step at launch is to check whether the Version of Google Play
128installed on the device supports the In-app Billing v2 API and
129subscriptions.</p>
130
131<p>To do this, create a CHECK_BILLING_SUPPORTED request Bundle that includes the
132required key-value pairs, together with</p>
133
134<ul>
135  <li>The <code>API_VERSION</code> key, assigning a value of 2.</li>
136  <li>The <code>BILLING_REQUEST_ITEM_TYPE</code> key, assigning a value of “subs”</li>
137</ul>
138
139<p>Send the request using <code>sendBillingRequest(Bundle)</code> and receive
140the response Bundle. You can extract the response from the
141<code>BILLING_RESPONSE_RESPONSE_CODE</code> key of the response. RESULT_OK
142indicates that subscriptions are supported.</p>
143
144<p>The sample app declares constants for the accepted
145<code>BILLING_REQUEST_ITEM_TYPE</code> values (from Consts.java):</p>
146
147<pre class="pretty-print">   // These are the types supported in the IAB v2
148   public static final String ITEM_TYPE_INAPP = "inapp";
149   public static final String ITEM_TYPE_SUBSCRIPTION = "subs";
150</pre>
151
152<p>It sets up a convenience method for building the request bundle (from BillingService.java):</p>
153
154<pre class="pretty-print">       protected Bundle makeRequestBundle(String method) {
155           Bundle request = new Bundle();
156           request.putString(Consts.BILLING_REQUEST_METHOD, method);
157           request.putInt(Consts.BILLING_REQUEST_<code>API_VERSION</code>, 2);
158           request.putString(Consts.BILLING_REQUEST_PACKAGE_NAME, getPackageName());
159           return request;
160       }
161</pre>
162
163<p>Here’s an example of how to test support for In-App Billing v2 and subscriptions
164(from BillingService.java):</p>
165
166<pre class="pretty-print">   /**
167    * Wrapper class that checks if in-app billing is supported.
168    */
169   class CheckBillingSupported extends BillingRequest {
170       public String mProductType = null;
171       public CheckBillingSupported() {
172           // This object is never created as a side effect of starting this
173           // service so we pass -1 as the startId to indicate that we should
174           // not stop this service after executing this request.
175           super(-1);
176       }
177
178       public CheckBillingSupported(String type) {
179           super(-1);
180           mProductType = type;
181       }
182
183       &#64;Override
184       protected long run() throws RemoteException {
185           Bundle request = makeRequestBundle("CHECK_BILLING_SUPPORTED");
186           if (mProductType != null) {
187               request.putString(Consts.<code>BILLING_REQUEST_ITEM_TYPE</code>, mProductType);
188           }
189           Bundle response = mService.sendBillingRequest(request);
190           int responseCode = response.getInt(Consts.<code>BILLING_RESPONSE_RESPONSE_CODE</code>);
191           if (Consts.DEBUG) {
192               Log.i(TAG, "CheckBillingSupported response code: " +
193                       ResponseCode.valueOf(responseCode));
194           }
195           boolean billingSupported = (responseCode == ResponseCode.RESULT_OK.ordinal());
196           ResponseHandler.checkBillingSupportedResponse(billingSupported, mProductType);
197           return Consts.BILLING_RESPONSE_INVALID_REQUEST_ID;
198       }
199   }
200</pre>
201
202<h2 id="purchase">Requesting a Subscription Purchase</h2>
203
204<p>Once you’ve checked the API Version as described above and determined that
205subscriptions are supported, you can present subscription products to the user
206for purchase. When the user has selected a subscription product and initiated a
207purchase, your app handles the purchase just as it would for other in-app
208products &mdash; by sending a REQUEST_PURCHASE request. You can then launch
209Google Play to display the checkout user interface and handle the financial
210transaction..
211
212<p>The REQUEST_PURCHASE includes a Bundle containing the item details, as
213described in the <a
214href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
215Overview</a>. For a subscription, the Bundle must also specify:</p>
216
217<ul>
218  <li>The <code>ITEM_ID</code> key, with a value that specifies a valid, published
219  subscription product.</li>
220  <li>The <code>ITEM_TYPE</code> key, with a value of “subs”
221  (<code>ITEM_TYPE_SUBSCRIPTION</code> in the sample app). If the request does not
222  specify the subscription's <code>ITEM_TYPE</code>, Google Play attempts to
223  handle the request as a standard in-app purchase (one-time purchase).</li>
224</ul>
225
226<p>Google Play synchronously returns a response bundle that includes
227<code>RESPONSE_CODE</code>, <code>PURCHASE_INTENT</code>, and
228<code>REQUEST_ID</code>. Your app uses the <code>PURCHASE_INTENT</code> to
229launch the checkout UI and the message flow proceeds exactly as described in <a
230href="{@docRoot}google/play/billing/v2/api.html#billing-message-
231sequence">Messaging sequence</a>.</p>
232
233<p>Here’s how the sample app initiates a purchase for a subscription, where
234<code>mProductType</code> is <code>ITEM_TYPE_SUBSCRIPTION</code> (from
235BillingService.java).</p>
236
237<pre class="pretty-print">   /**
238    * Wrapper class that requests a purchase.
239    */
240   class RequestPurchase extends BillingRequest {
241       public final String mProductId;
242       public final String mDeveloperPayload;
243       public final String mProductType;
244
245. . .
246
247       &#64;Override
248       protected long run() throws RemoteException {
249           Bundle request = makeRequestBundle("REQUEST_PURCHASE");
250           request.putString(Consts.BILLING_REQUEST_ITEM_ID, mProductId);
251           request.putString(Consts.<code>BILLING_REQUEST_ITEM_TYPE</code>, mProductType);
252           // Note that the developer payload is optional.
253           if (mDeveloperPayload != null) {
254               request.putString(Consts.BILLING_REQUEST_DEVELOPER_PAYLOAD, mDeveloperPayload);
255           }
256           Bundle response = mService.sendBillingRequest(request);
257           PendingIntent pendingIntent
258                   = response.getParcelable(Consts.BILLING_RESPONSE_PURCHASE_INTENT);
259           if (pendingIntent == null) {
260               Log.e(TAG, "Error with requestPurchase");
261               return Consts.BILLING_RESPONSE_INVALID_REQUEST_ID;
262           }
263
264           Intent intent = new Intent();
265           ResponseHandler.buyPageIntentResponse(pendingIntent, intent);
266           return response.getLong(Consts.BILLING_RESPONSE_REQUEST_ID,
267                   Consts.BILLING_RESPONSE_INVALID_REQUEST_ID);
268       }
269
270       &#64;Override
271       protected void responseCodeReceived(ResponseCode responseCode) {
272           ResponseHandler.responseCodeReceived(BillingService.this, this, responseCode);
273       }
274   }
275</pre>
276
277<h2 id="restoring">Restoring Transactions</h2>
278
279<p>Subscriptions always use  the <em>managed by user account</em> purchase type,
280so that you can restore a record of subscription transactions on the device when
281needed. When a user installs your app onto a new device, or when the user
282uninstalls/reinstalls the app on the original device, your app should restore
283the subscriptions that the user has purchased.</p>
284
285<p>The process for restoring subscriptions transactions is the same as described
286in <a
287href="{@docRoot}google/play/billing/v2/api.html#billing-message-
288sequence">Messaging sequence</a>. Your app sends a
289<code>RESTORE_TRANSACTIONS</code> request to Google Play. Google Play sends two
290broadcast intents as asynchronous responses &mdash; a <code>RESPONSE_CODE</code>
291intent and a <code>PURCHASE_STATE_CHANGED</code> intent.</p>
292
293<p>The <code>PURCHASE_STATE_CHANGED</code> intent contains a notification ID
294that your app can use to retrieve the purchase details, including the purchase
295token, by sending a standard <code>GET_PURCHASE_INFORMATION</code> request. The
296<code>Bundle</code> returned in the call includes an JSON array of order objects
297corresponding to subscription (and in-app product) purchases that you can
298restore locally.</p>
299
300<p>Your app can store the restored purchase state and other transaction details
301in the way that best meets your needs. Your app can use it later to check the
302subscription validity, although please read the <a
303href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
304Design</a> document for best practices for maintaining the security of your
305data.</p>
306
307<h2 id="validity">Checking Subscription Validity</h2>
308
309<p>Subscriptions are time-bound purchases that require successful billing
310recurrences over time to remain valid. Your app should check the validity of
311purchased subscriptions at launch or prior to granting access to subscriber
312content.</p>
313
314<p>With In-app Billing, you validate a subscription by keeping track of its
315purchase state and then checking the state whenever needed. Google Play
316provides two ways to let you know when the purchase
317state of a subscription changes:</p>
318
319<ul>
320  <li><em>In-app Billing Notifications</em>. Google Play pushes a notification
321  to your app to indicate a change in the purchase state of a subscription. Your app can
322  store the most recent purchase state for a given purchase token and then check
323  that state at run time, as needed.</li>
324  <li><em>Google Play Android Developer API</em>. You can use this HTTP-based
325  API to poll Google Play for the current purchase state of a subscription. You
326  can store the purchased state for each <code>purchaseToken</code> on your
327  backend servers. For more information, see <a href="#play-dev-api">Google Play
328  Android Developer API</a>, below.</li>
329</ul>
330
331<p>For most use-cases, especially those where backend servers are already keeping
332track of subscribed users, implementing a combination of both methods is the
333recommended approach. A typical implementation might work like this:</p>
334
335<ul>
336  <li>When the user successfully purchases a new subscription, your app notifies a
337  backend server, which stores the purchase token, user name, and other
338  information in a secure location.</li>
339  <li>Since your app cannot know the expiration date, your server can poll Google
340  Play to get the expiration and store it with the purchase token and other
341  data.</li>
342  <li>Because your server now knows the expiration date, it does not need to poll
343  Google Play again until after the expiration date, at which time it can confirm
344  that the subscription was not cancelled.</li>
345  <li>On the client side, your app can continue to update the server whenever the
346  purchase state changes, storing the state locally.</li>
347</ul>
348
349<p>If you are using both notifications and the Google Play Android Developer API to validate subscriptions, we recommend the following:</p>
350
351<ul>
352  <li>If your app wants to check validity but you can’t reach your server (or
353you don’t have a server), use the latest purchase state received by
354notification.</li>
355  <li>If you have a server and it’s reachable, always give preference to the
356purchase state obtained from your server over the state received in
357notifications.</li>
358</ul>
359
360<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>
361
362<p>Regardless of the approach you choose, your app should check subscriptions
363and validity at launch, such as prior to accessing subscriber content, game
364levels, and so on.</p>
365
366<p class="table-caption"><strong>Table 1.</strong> Summary of purchaseState
367values for subscription purchases, as received with a
368<code>PURCHASE_STATE_CHANGED</code> intent.</p>
369
370<table>
371<tr>
372<th>State</th><th>purchaseState Value</th><th>Comments</th>
373</tr>
374<tr>
375<td>Purchased successfully</td><td><code>0</code></td><td>Sent at original purchase only (not at recurring billing cycles).</td></tr>
376<td>Cancelled</td><td><code>1</code></td><td>Sent at original purchase only if the purchase has failed for some reason. </td></tr>
377<td>Refunded</td><td><code>2</code></td><td>The purchase was refunded.</code></td></tr>
378<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.
379</td></tr>
380</table>
381
382
383<h2 id="viewstatus">Letting the User Cancel or View Subscriptions</h2>
384
385<p>In-app Billing does not currently provide an API to let users directly view or cancel
386subscriptions from within the purchasing app. Instead, users can launch the Play
387Store app on their devices and go to the My Apps screen to manage subscriptions. In My Apps,
388users can see a list of their subscriptions organized by application. Tapping one of the
389subscriptions loads the app's product page, from which users can see active subscriptions
390and billing status and cancel subscriptions as needed.</p>
391
392<p>To make it easier for users to find and manage their subscriptions from inside your app,
393we recommend that you offer a "View My Subscriptions" or "Manage Subscriptions" option in
394your UI that directly loads your app's product page in the Play Store app.</p>
395
396<p>To do this, create an intent with the <a
397href="{@docRoot}reference/android/content/Intent.html#ACTION_VIEW">ACTION_VIEW</a>
398action and include the <code>market://</code> URI (rather than the <code>http://</code>
399URI) of your app's details page. Here’s an example:</p>
400
401<pre style="pretty-print">Intent intent = new Intent(Intent.ACTION_VIEW);
402intent.setData(Uri.parse("market://details?id=com.example.app"));
403startActivity(intent);</pre>
404
405<p>For more information, see
406  <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to Your Products</a>.</p>
407
408<h2 id="purchase-state-changes">Recurring Billing, Cancellation, and Changes In Purchase State</h2>
409
410<p>Google Play notifies your app when the user completes the purchase of a
411subscription, but the purchase state does not change over time, provided that
412recurring billing takes place successfully. Google Play does not notify your app
413of a purchase state change <em>until the subscription expires because of
414non-payment or user cancellation</em>. </p>
415
416<p>Over the life of a subscription, your app does not need to initiate any
417recurring billing events &mdash; those are all handled by Google Play and they
418are transparent to your application if billing is successful.</p>
419
420<p>When the user cancels a subscription during an active billing cycle, Google
421Play <em>does not</em> notify your app immediately of the change in purchase
422state. Instead, it waits until the end of the active billing cycle and then
423notifies your app that the purchase state has changed to "Expired". </p>
424
425<p>Similarly, if payment for the next billing cycle fails, Google Play waits
426until the end of the active billing cycle and then notifies your app at that time that the
427purchase state has changed to "Expired".</p>
428
429<p>Your app can handle user cancellation and non-payment in the same way, since both cause
430a change to the same "Expired" purchase state. Once the purchase state has become "Expired",
431your app does not need to grant further access to the subscription content.</p>
432
433<h2 id="modifying">Modifying Your App for Subscriptions</h2>
434
435<p>For subscriptions, you make the same types of modifications to your app as
436are described in <a
437href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-implement">
438Modifying your Application Code</a>.</p>
439
440<p>Note that, in your UI that lets users view and select subscriptions for
441purchase, you should add logic to check for purchased subscriptions and validate
442them. Your UI should not present subscriptions if the user has already purchased
443them.</p>
444
445
446
447
448
449