Plugin - In App Purchase - Google

What you will learn in this chapter
Integrate In App Purchase Google plugin with your App
Download avm-google-in-app-purchase-v2.zip , avm-google-in-app-purchase-v3.zip
Good Read - Appemble Plugin In App Purchase using Apple, In App Purchase using Amazon

In App Purchase plugin allows you to add purchase or subscription of products or premium features from your app. The premium features are purchased from the market place where your app is published and downloaded from. AVM supports the following market place - Apple, Google and Amazon.

Each market place has a different technical solution to complete the in-app purchase. This plugin greatly simplifies and minimizes the time it takes to integrate the in-app purchases for different market places by providing actions common actions

  • REQUEST_PURCHASE to make a purchase.
  • RESTORE_TRANSACTIONS to restore the purchase history.

Once the product gets purchased (or cancelled, subscription expired), the plugin generates an event ON_PRODUCT_PURCHASE_STATE_CHANGE. You can associate an action with this event to inform your server about this.

Market places generally support 3 types of products to be purchased

Product Type Description
Consumables It is a type of product (feature, content or services) that can be bought multiple times in an app and has a temporary affect. The market place does not track the purchase of this product. This type of product is generally consumed within the application for example fuel or coins.
Non-Consumable or Entitled Products These types of products are bought only once and provide a permanent benefit. They are available even after the app is removed and reinstalled.
Subscriptions It is a type of product (feature, content or services) that is sold from inside your app with recurring billing period for example, monthly or yearly.

Integrate In App Purchase Google plugin with your App

Google In-app billing service has two versions V2 and V3 and so does this plugin. The V3 simplifies the integration of In-app Billing. It is generally recommended that new apps should use latest versions of Google In-app Billing Service. You can find more information about V2 and V3 and their differences at the Google’s In-app Billing documentation.

Plugin Integration (v2)

  1. Download `avm-google-in-app-purchase-v2.zip`_ and import plugin to your workspace. The zip file includes the plugin and a sample project.

  2. Add the plugin appemble-google-in-app-purchase-v2 to your project.

    • Click on your project -> Properties -> Android
    • Click on Add.
    ../_images/in-app-purchase-google.png

    Note

    You can remove the library appemble-android-library from the list of libraries included as the appemble-google-in-app-purchase-v2 library already includes it.

  3. Create the tables _inappbilling_products and _inappbilling_purchase_history in the content database. Your content database is located in th assets folder. You can use the SQL script located in appemble-google-in-app-purchase-v2/extras/content-db-script.sql. See Working with local content database on how to modify content database. The table _inappbilling_products holds the list of available products, descriptions and price. The table _inappbilling_purchase_history holds the transaction history including the date of transaction.

  4. Populate the table _inappbilling_products - This can be done in two ways.
    • Statically - You can populate this table before packaging the app. If the table is pre-populated then for adding new products, you may have to release a new version of the app.
      insert into _inappbilling_products (_id, type, title, description, price, orderby) values
          ('com.mycompany.myproduct1', 'SUBSCRIPTION', 'Acme', 'Best cleaner', 4.99, 1);
      
    • Dynamically - Alternatively you can get the list of products from your server dynamically before displaying the screen that lists the products. If the list of products is dynamically downloaded, then new products can be added any time and the app will make them available for purchase. You can download the list of products on the event ON_APP_LAUNCH or ON_CREATE_SCREEN event for the screen that displays the list of products available for selling.

      <screen_deck name="my app" starting_screen_name="first_screen">
          <action name="CALL_URL" event_list="ON_APP_LAUNCH" target="http://www.yourserver.com/download/listofproducts"
              remote_data_save_locally="true" remote_data_format="JSON"/>
      </screen_deck>
      

    In the above example, the target URL will download the product list in JSON format and it will be saved in the table _inappbilling_products. The JSON array returned from the server must be named _inappbilling_products. The JSON Object must have columns _id, type, title, description, price and orderby.

    Note

    In the tutorial appemble-google-tutorial-in-app-purchase-v2 the sample products have been added statically.

  5. Define your In App purchase screen -

    • Define a screen where screen_type="com.appemble.inapppurchase.INAPPBILLING"
    • Call action com.appemble.inapppurchase.SET_APP_KEY on event_list=”ON_CREATE_SCREEN”. For better security, you can download the app key from the server first and then pass it on the action com.appemble.inapppurchase.SET_APP_KEY.
    <screen allowed_layouts="BOTH" allow_reorientation="true" scroll="VERTICAL"
            menuOrder="-1" name="inappbilling" on_resume_update="1" screen_type="com.appemble.inapppurchase.INAPPBILLING"
            width="100.0" height="100.0" restore_transactions_on_create="true">
            <actions>
                    <action action_name="com.appemble.inapppurchase.SET_APP_KEY" event_list="ON_CREATE_SCREEN"
        input_parameter_list="CONSTANT:your app licence key"
                            target_parameter_list="app_key" />
    </actions>
    
    • Add controls to display products for purchase
  6. Get license key for your app - App key is needed so that your app can interact with the Google In-app Billing service. Your application licence key can be obtained from the Google’s Developer Console. In order to obtain the licence key do the following.

    • Login to Google’s Developer Console.
    • Upload your application package(yourapp.apk). DO NOT PUBLISH.
    • Click on your app.
    • Click on Services and API. Scroll down and copy the License Key and paste it in input_parameter_list=”CONSTANT:your app licence key”.
  7. Add Request Purchase action - Products are purchased by calling the action com.appemble.inapppurchase.REQUEST_PURCHASE. You can call this action when the user taps to purchase a product. This action invokes the User Interface where the user can pay for the product. Example

    <!-- product list control -->
    <control appearance_name="1" data_type="CURSOR"
        local_data_source="select _id, _id as product_id, description,('$ '||price) as price, title, type as managed_type from _inappbilling_products order by orderby"
        name="product_list" on_resume_update="1" size="2" type="LIST" width="100.0"
        x="0.0" y="1.0" height="50" ios_list_style="sectioned_list">
        <control appearance_name="13" data_type="VARCHAR"
            ellipsized="1" field_name="title" height="25.0" name="title"
            on_resume_update="1" size="80" type="TEXT" width="75.0" x="2.0" y="1.0" />
        <control appearance_name="13" data_type="VARCHAR"
            ellipsized="1" field_name="price" height="25.0" name="price"
            on_resume_update="1" size="80" type="TEXT" width="17.0" x="70.0" y="1.0" />
        <!-- <control appearance_name="13" data_type="VARCHAR" ellipsized="1"
            field_name="Description" height="7.0" name="product_description" on_resume_update="1"
            size="80" type="TEXT" width="80.0" x="2.0" y="8.0" /> -->
        <control appearance_name="1"
            default_value="IMAGE:brown_arrow.png" height="25.0" name="right_arrow"
            on_resume_update="1" size="1" type="IMAGE" width="6.0" x="88.0" y="1.0" />
        <control appearance_name="13" data_type="VARCHAR"
            field_name="product_id" height="0.0" is_visible="0" name="product_id"
            on_resume_update="1" size="80" type="TEXT" width="0.0" x="0.0" y="0.0" />
        <control appearance_name="13" data_type="VARCHAR"
            field_name="managed_type" height="0.0" is_visible="0" name="type"
            on_resume_update="1" size="80" type="TEXT" width="0.0" x="0.0" y="0.0" />
        <action action_name="com.appemble.inapppurchase.REQUEST_PURCHASE" event_list="TAP"
            input_parameter_list="product_id, managed_type, CONSTANT:auser"
            target_parameter_list="product_id, managed_type, developer_payload" />
    </control>
    
  8. Store the transaction upon completion - The plugin raises the event “com.appemble.inapppurchase.ON_PRODUCT_PURCHASE_STATE_CHANGE” when there is a change in the product state. Define an action in <screen> on this event to do something when the transaction is complete. For example display a message on completion of the transaction and REFRESH.

    <screen allowed_layouts="BOTH" allow_reorientation="true" scroll="VERTICAL"
        menuOrder="-1" name="inappbilling" on_resume_update="1" screen_type="com.appemble.inapppurchase.INAPPBILLING"
        width="100.0" height="100.0" restore_transactions_on_create="true">
        <actions>
            <action action_name="ALERT" event_list="com.appemble.inapppurchase.ON_PRODUCT_PURCHASE_STATE_CHANGE"
                input_parameter_list="CONSTANT:ON_PRODUCT_PURCHASE_COMPLETE, CONSTANT:SomeMessage"
                target_parameter_list="title, message" />
            <action action_name="REFRESH" remote_data_also="false" event_list="com.appemble.inapppurchase.ON_PRODUCT_PURCHASE_STATE_CHANGE"/>
    

    Note

    Actions that gets executed on this event can be defined on the tag <screendeck> or <screen>. Any UI related actions like REFRESH must only be defined in the tag <screen>.

    The product purchase states are 1 (canceled), 2 (refunded), or 3 (expired, for subscription purchases only). You can call an action on this event to inform your server that a new item has been purchased or subscription has

    The following parameters are available to the actions executed on this event.

    Attribute

    Description

    order_id

    A unique order identifier for the transaction. This corresponds to the Google Wallet Order ID.

    product_id

    The item’s product identifier. Every item has a product ID, which you must specify in the application’s product list on the Google Play Developer Console.

    purchase_time

    The time the product was purchased, in milliseconds since the epoch (Jan 1, 1970).

    purchase_state

    The purchase state of the order. Possible values are 0 (purchased), 1 (canceled), 2 (refunded), or 3 (expired, for subscription purchases only).

    purchase_token

    A token that uniquely identifies a subscription purchase for a given item and user pair. You can use the token to specify the subscription when querying for subscription validity.

    developer_payload

    A developer-specified string that contains supplemental information about an order. You can specify a value for this field when you make a REQUEST_PURCHASE request.

    Note

    The above descriptions were obtained from Android’s Documentation.

  9. Download purchase history - You can do this by setting the attribute restore_transactions_on_create="true" for the screen of screen_type=INAPPBILLING. or by calling the action com.appemble.inapppurchase.RESTORE_TRANSACTIONS. The action “com.appemble.inapppurchase.RESTORE_TRANSACTIONS” must be initiated from the screen of screen_type=”com.appemble.inapppurchase.INAPPBILLING”

Sample Code

See the sample code for this screen is shown below. It is from the tutorial appemble-google-tutorial-in-app-purchase-v2\google-in-app-purchase-v2-app-definition\inappbilling.xml.

 <screens>
     <screen allowed_layouts="BOTH" allow_reorientation="true" scroll="VERTICAL"
         menuOrder="-1" name="inappbilling" on_resume_update="1" screen_type="com.appemble.inapppurchase.INAPPBILLING"
         width="100.0" height="100.0" restore_transactions_on_create="true">
         <actions>
             <action action_name="ALERT" event_list="com.appemble.inapppurchase.ON_PRODUCT_PURCHASE_STATE_CHANGE"
                 input_parameter_list="CONSTANT:ON_PRODUCT_PURCHASE_COMPLETE, CONSTANT:SomeMessage"
                 target_parameter_list="title, message" />
             <action action_name="REFRESH" remote_data_also="false" event_list="com.appemble.inapppurchase.ON_PRODUCT_PURCHASE_STATE_CHANGE"/>
             <action action_name="com.appemble.inapppurchase.SET_APP_KEY" event_list="ON_CREATE_SCREEN"
                 input_parameter_list="CONSTANT:your app key"
                 target_parameter_list="app_key" />
         </actions>
         <title_controls>
             <control appearance_name="6" default_value="Subscription Options"
                 height="6.0" name="title_product_purchase_list" on_resume_update="1"
                 size="255" type="TEXT" width="56.0" x="24.0" y="2.0" />
         </title_controls>
         <!-- product list control -->
         <controls>
             <control appearance_name="1" data_type="CURSOR"
                 local_data_source="select _id, _id as product_id, description,('$ '||price) as price, title, type as managed_type from _inappbilling_products order by orderby"
                 name="product_list" on_resume_update="1" size="2" type="LIST" width="100.0"
                 x="0.0" y="1.0" height="50" ios_list_style="sectioned_list">
                 <control appearance_name="13" data_type="VARCHAR"
                     ellipsized="1" field_name="title" height="25.0" name="title"
                     on_resume_update="1" size="80" type="TEXT" width="75.0" x="2.0" y="1.0" />
                 <control appearance_name="13" data_type="VARCHAR"
                     ellipsized="1" field_name="price" height="25.0" name="price"
                     on_resume_update="1" size="80" type="TEXT" width="17.0" x="70.0" y="1.0" />
                 <!-- <control appearance_name="13" data_type="VARCHAR" ellipsized="1"
                     field_name="Description" height="7.0" name="product_description" on_resume_update="1"
                     size="80" type="TEXT" width="80.0" x="2.0" y="8.0" /> -->
                 <control appearance_name="1"
                     default_value="IMAGE:brown_arrow.png" height="25.0" name="right_arrow"
                     on_resume_update="1" size="1" type="IMAGE" width="6.0" x="88.0" y="1.0" />
                 <control appearance_name="13" data_type="VARCHAR"
                     field_name="product_id" height="0.0" is_visible="0" name="product_id"
                     on_resume_update="1" size="80" type="TEXT" width="0.0" x="0.0" y="0.0" />
                 <control appearance_name="13" data_type="VARCHAR"
                     field_name="managed_type" height="0.0" is_visible="0" name="type"
                     on_resume_update="1" size="80" type="TEXT" width="0.0" x="0.0" y="0.0" />
                 <action action_name="com.appemble.inapppurchase.REQUEST_PURCHASE" event_list="TAP"
                     input_parameter_list="product_id, managed_type, CONSTANT:auser"
                     target_parameter_list="product_id, managed_type, developer_payload" />
             </control>
             <control appearance_name="5" data_type="VARCHAR" ellipsized="1"
                 name="edit_subscription" on_resume_update="1" size="80" type="PUSHBUTTON"
                 default_value="Edit Subscription" x="10.0" y="90.0" width="40"
                 height="7.0">
                 <action action_name="com.appemble.inapppurchase.REQUEST_PURCHASE" event_list="TAP"
                     input_parameter_list="product_id, managed_type, userid, CONSTANT:edit_subscription"
                     target_parameter_list="product_id, managed_type, developer_payload, action" />
             </control>
             <control appearance_name="5" data_type="VARCHAR" ellipsized="1"
                 name="close_screen" on_resume_update="1" type="PUSHBUTTON"
                 default_value="Close" x="55.0" y="90.0" width="40" height="7.0">
                 <action action_name="CLOSE_SCREEN" event_list="TAP" />
             </control>
         </controls>
     </screen>
 </screens>

Note

In case you want to retrieve the purchase history on the same screen, set the attribute restore_transactions_on_create="true".

Plugin Integration (v3)