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