Home | History | Annotate | Download | only in v2
      1 page.title=Implementing Subscriptions  <span style="font-size:16px;">(IAB Version 2)</span>
      2 excludeFromSuggestions=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 
     25 specific to subscriptions with the Version 2 API. To understand how  
     26 subscriptions 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
     32 subscriptions, an updated Version of the In-app Billing sample app is available.
     33 You can download the sample app from the Android SDK repository using the
     34 Android SDK Manager. For details, see <a
     35 href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-download">
     36 Downloading 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
     41 model, sending billing requests to the Play Store application over interprocess
     42 communication (IPC) and receiving purchase responses from the Play Store app in
     43 the form of asynchronous broadcast intents. Your application does not manage any
     44 network connections between itself and the Google Play server or use any special
     45 APIs from the Android platform.</p>
     46 
     47 <p>Your app also uses the standard In-app Billing components &mdash; a billing
     48 Service for sending requests, a BroadcastReceiver for receiving the responses,
     49 and a security component for verifying that the response was sent by Google
     50 Play. Also recommended are a response Handler for processing notifications,
     51 errors, and status messages, and an observer for sending callbacks to your
     52 application as needed. All of these components and their interactions are
     53 described in full in the <a
     54 href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
     55 Overview</a> and related documents.</p>
     56 
     57 <p>To initiate different types of billing communication with Google Play, your
     58 app will use the standard set of in-app billing requests and receive the same
     59 responses. 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
     65 token, a string value that uniquely identifies (and associates) a user ID and a
     66 subscription ID. Google Play generates the purchase token when the user
     67 completes the purchase of a subscription product (and payment is approved by
     68 Google Wallet) and then sends it to the purchasing app on the device through the
     69 In-app Billing API. </p>
     70 
     71 <p>At the conclusion of a <code>PURCHASE_REQUEST</code> message flow, your app
     72 can retrieve the purchase token and other transaction details by initiating a
     73 <code>GET_PURCHASE_INFORMATION</code> request. The Bundle returned by the call
     74 contains an JSON array of order objects. In the order corresponding to the
     75 subscription purchase, the token is available in the <code>purchaseToken</code>
     76 field. </p>
     77 
     78 <p>An example of a JSON order object that includes a subscription purchase token
     79 is 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
     95 pass it to your backend servers, which can then use it to query the billing
     96 status or cancel the subscription remotely. If your app will store the token
     97 locally, please read the <a
     98 href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
     99 Design</a> document for best practices for maintaining the security of your
    100 data.</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
    105 support the In-app Billing v2 API (Google Play 3.5 and higher). For your app,
    106 an essential first step at launch is to check whether the Version of Google Play
    107 installed on the device supports the In-app Billing v2 API and
    108 subscriptions.</p>
    109 
    110 <p>To do this, create a CHECK_BILLING_SUPPORTED request Bundle that includes the
    111 required 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
    119 the response Bundle. You can extract the response from the
    120 <code>BILLING_RESPONSE_RESPONSE_CODE</code> key of the response. RESULT_OK
    121 indicates 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>Heres 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 youve checked the API Version as described above and determined that
    184 subscriptions are supported, you can present subscription products to the user
    185 for purchase. When the user has selected a subscription product and initiated a
    186 purchase, your app handles the purchase just as it would for other in-app
    187 products &mdash; by sending a REQUEST_PURCHASE request. You can then launch
    188 Google Play to display the checkout user interface and handle the financial
    189 transaction..  
    190 
    191 <p>The REQUEST_PURCHASE includes a Bundle containing the item details, as
    192 described in the <a
    193 href="{@docRoot}google/play/billing/v2/api.html">In-app Billing
    194 Overview</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
    208 launch the checkout UI and the message flow proceeds exactly as described in <a
    209 href="{@docRoot}google/play/billing/v2/api.html#billing-message-
    210 sequence">Messaging sequence</a>.</p>
    211 
    212 <p>Heres how the sample app initiates a purchase for a subscription, where
    213 <code>mProductType</code> is <code>ITEM_TYPE_SUBSCRIPTION</code> (from
    214 BillingService.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,
    259 so that you can restore a record of subscription transactions on the device when
    260 needed. When a user installs your app onto a new device, or when the user
    261 uninstalls/reinstalls the app on the original device, your app should restore
    262 the subscriptions that the user has purchased.</p>
    263 
    264 <p>The process for restoring subscriptions transactions is the same as described
    265 in <a
    266 href="{@docRoot}google/play/billing/v2/api.html#billing-message-
    267 sequence">Messaging sequence</a>. Your app sends a
    268 <code>RESTORE_TRANSACTIONS</code> request to Google Play. Google Play sends two
    269 broadcast intents as asynchronous responses &mdash; a <code>RESPONSE_CODE</code>
    270 intent and a <code>PURCHASE_STATE_CHANGED</code> intent.</p>
    271 
    272 <p>The <code>PURCHASE_STATE_CHANGED</code> intent contains a notification ID
    273 that your app can use to retrieve the purchase details, including the purchase
    274 token, 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
    276 corresponding to subscription (and in-app product) purchases that you can
    277 restore locally.</p>
    278 
    279 <p>Your app can store the restored purchase state and other transaction details
    280 in the way that best meets your needs. Your app can use it later to check the
    281 subscription validity, although please read the <a
    282 href="{@docRoot}google/play/billing/billing_best_practices.html">Security and
    283 Design</a> document for best practices for maintaining the security of your
    284 data.</p>
    285 
    286 <h2 id="validity">Checking Subscription Validity</h2>
    287 
    288 <p>Subscriptions are time-bound purchases that require successful billing
    289 recurrences over time to remain valid. Your app should check the validity of
    290 purchased subscriptions at launch or prior to granting access to subscriber
    291 content.</p>
    292 
    293 <p>With In-app Billing, you validate a subscription by keeping track of its
    294 purchase state and then checking the state whenever needed. Google Play 
    295 provides two ways to let you know when the purchase
    296 state 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
    311 track of subscribed users, implementing a combination of both methods is the
    312 recommended 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 cant reach your server (or
    332 you dont have a server), use the latest purchase state received by
    333 notification.</li>
    334   <li>If you have a server and its reachable, always give preference to the
    335 purchase state obtained from your server over the state received in
    336 notifications.</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
    342 and validity at launch, such as prior to accessing subscriber content, game
    343 levels, and so on.</p>
    344 
    345 <p class="table-caption"><strong>Table 1.</strong> Summary of purchaseState
    346 values 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
    365 subscriptions from within the purchasing app. Instead, users can launch the Play
    366 Store app on their devices and go to the My Apps screen to manage subscriptions. In My Apps,
    367 users can see a list of their subscriptions organized by application. Tapping one of the
    368 subscriptions loads the app's product page, from which users can see active subscriptions
    369 and 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, 
    372 we recommend that you offer a "View My Subscriptions" or "Manage Subscriptions" option in
    373 your 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 
    376 href="{@docRoot}reference/android/content/Intent.html#ACTION_VIEW">ACTION_VIEW</a>
    377 action and include the <code>market://</code> URI (rather than the <code>http://</code>
    378 URI) of your app's details page. Heres an example:</p>
    379 
    380 <pre style="pretty-print">Intent intent = new Intent(Intent.ACTION_VIEW);
    381 intent.setData(Uri.parse("market://details?id=com.example.app"));
    382 startActivity(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
    390 subscription, but the purchase state does not change over time, provided that
    391 recurring billing takes place successfully. Google Play does not notify your app
    392 of a purchase state change <em>until the subscription expires because of
    393 non-payment or user cancellation</em>. </p>
    394 
    395 <p>Over the life of a subscription, your app does not need to initiate any
    396 recurring billing events &mdash; those are all handled by Google Play and they
    397 are transparent to your application if billing is successful.</p>
    398 
    399 <p>When the user cancels a subscription during an active billing cycle, Google
    400 Play <em>does not</em> notify your app immediately of the change in purchase
    401 state. Instead, it waits until the end of the active billing cycle and then
    402 notifies 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
    405 until the end of the active billing cycle and then notifies your app at that time that the
    406 purchase 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
    409 a change to the same "Expired" purchase state. Once the purchase state has become "Expired",
    410 your 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
    415 are described in <a
    416 href="{@docRoot}google/play/billing/v2/billing_integrate.html#billing-implement">
    417 Modifying your Application Code</a>.</p>
    418 
    419 <p>Note that, in your UI that lets users view and select subscriptions for
    420 purchase, you should add logic to check for purchased subscriptions and validate
    421 them. Your UI should not present subscriptions if the user has already purchased
    422 them.</p>
    423 
    424 
    425 
    426 
    427 
    428