Requirements
Prerequisite knowledge
Experience building apps for Android with Flash Builder or Flash Professional and Adobe AIR will help you make the most of this article.
Required products
Flash Builder (Download trial)
Adobe Animate CC
Adobe AIR SDK
Additional required other products
Milkman Games In-App Billing Extension for Android
User Level
Intermediate

With the In-App Billing Extension for Android from Milkman Games, you can rapidly integrate In-App-app purchasing into your mobile AIR application using ActionScript 3.
 
The In-App Billing Extension for Android is a 100 percent native Java solution that enables you to:
 
  • Offer your app for free and earn revenue within-app purchases
  • Make a purchase with just a few lines of code
  • Jumpstart development with a complete sample application, ActionScript 3 documentation, and a getting started guide
  • Invoke testing methods to verify purchases before your app goes live

 
Installing the latest AIR SDK

This native extension requires-the AIR 3.5 SDK or a later version. You can download the latest AIR SDK from http://www.adobe.com/special/products/air/sdk/. If you haven't already installed the AIR 3.5 or later SDK for your Flash Professional CS6 or Flash Builder IDE, follow the instructions below.
 
 
Enabling the latest AIR SDK in Flash Professional CS6
  1. Unzip the AIR SDK package on your hard drive.
  2. Launch Flash Professional CS6.
  3. Choose Help > Manage AIR SDK.
  4. Click the Plus (+) Button and navigate to the location of the unzipped AIR SDK.
  5. Click OK.
  6. Choose File > Publish Settings.
  7. Select the AIR 3.5 (or Later) SDK for iOS as the Target.
 
Enabling the latest AIR SDK in Flash Builder  on Windows
  1. Unzip the AIR SDK package on your hard drive.
  2. Close Flash Builder.
  3. Locate the Flash Builder SDK directory. On Windows, this is typically c:\Program Files\Adobe\Adobe Flash Builder4.6\sdks.
  4. Make a copy of the current Flex SDK directory, and give it a descriptive name. For instance, copy the 4.6.0 SDK folder inside /sdks and name the copy 4.6.0_AIR37.
  5. Copy and paste the contents of the AIR 3.5 SDK into the 4.6.0_AIR37 directory. Accept all changes.
  6. Edit the flex-sdk-description.xml file inside the new directory, and change the value of the <name> tag to match the version of the latest AIR SDK- for instance, Flex 4.6.0 (AIR 3.7).
  7. Open Flash Builder and choose Project > Properties > Flex Compiler >Configure Flex SDKs.
  8. Click Add and navigate to the new folder location.
Enabling the latest AIR SDK in Flash Builder on OS X
 
  1. Copy the contents AIR SDK package to your hard drive.
  2. Close Flash Builder.
  3. Locate the Flash Builder SDK directory. On OS X, it is typically /Applications/Adobe Flash Builder 4.6/sdks/.
  4. Create a new folder inside the /Flash Builder 4.6/sdks/ folder named after the latest SDK- for instance, AIR37SDK, and copy the contents of the AIR SDK package thatyou downloaded in step 1 into it.
  5. Open the Terminal, and merge the new AIR SDK files into your current SDK directory:
sudo cp -Rp /Applications/Adobe\ Flash\ Builder\ 4.6/sdks/AIR37SDK/ /Applications/Adobe\ Flash\ Builder\ 4.6/sdks/4.6.0/
  1. Edit the flex-sdk-description.xml file inside the new directory, and change thevalue of the <name> tag to match the version of the latest AIR SDK-for instance, Flex 4.6.0 (AIR 3.7).
  2. Open Flash Builder and choose Project > Properties > Flex Compiler >Configure Flex SDKs.
  3. Click Add and navigate to the new folder location.

 
Including the library

The next step is to add the com.milkmangames.extensions.AndroidIAB.ane library to your project. (If you are not using FlashBuilder 4.6 and later or Flash Professional CS6 and later you'll need to add the AndroidIABAPI.swc library instead.)
 
In Flash Professional CS6:
 
  1. Create a new project of the type AIR for Android.
  2. Choose File > Publish Settings.
  3. Click the wrench icon next to Script for ActionScript Settings.
  4. Select the Library Path tab.
  5. Click Browse For Native Extension (ANE) File and select the com.milkmangames.extensions.AndroidIAB.ane file.
  6. Select Player Settings.
  7. Select the Permissions tab and enable INTERNET.
  8. Check Manually Manage Permissions and Manifest Additions for this App and press OK.
In Flash Builder 4.6 and later:
 
  1. Go to Project Properties (right-click your project in Package Explorer and select Properties).
  2. Select ActionScript Build Path and click the Native Extensions tab.
  3. Click Add ANE and navigate to the com.milkmangames.nativeextensions.AndroidIAB.anefile .
  4. Select ActionScript Build Packaging > Google Android
  5. Select the Native Extensions tab and enable the Package checkbox for the extension
In FlashDevelop:
 
  1. Copy the AndroidIABAPI.swc file to your project folder.
  2. Inthe explorer panel, right-click the SWC and select AddTo Library.
  3. Right-click the SWC file in the explorer panel again, select Options,and then select External Library.

 
Updating your application descriptor file

You need to configure your AIR application descriptor file to use the AIR 3.5 SDK (or later), include the In-AppBilling extension, and update the Android manifest additions with some AndroidBilling specific settings. (If you're using Flash Professional, make sure you've followed the steps above for Including the Library in Flash ProfessionalCS6, to ensure the changes you make are not overwritten.)  For a working example, see example/app.xml.
 
  1. Set your AIR SDK to 3.5 or later in the app descriptor file:
<application xmlns="http://ns.adobe.com/air/application/3.5">
  1. Include a link to the extension in the descriptor:
<extensions> <extensionID>com.milkmangames.extensions.AndroidIAB</extensionID> </extensions>
  1. Update your Android manifest additions. The android.permission.INTERNET and com.android.vending.BILLING permissions must be present for In-App Billing to work. You also must add the minSdkVersion and targetSdkVersion tags as shown below:
<android> <manifestAdditions><![CDATA[ <manifest android:installLocation="auto"> <uses-sdk android:targetSdkVersion="12"/> <uses-sdk android:minSdkVersion="8"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="com.android.vending.BILLING"/> </manifest> ]]></manifestAdditions> </android>

 
Building the application and uploading a draft to Google Play

  1. Save your work, and build an APK file from your application. Although there is nocode in the application yet, it's a good idea to build it now, as Google Play requires you to upload an APK before In-App Billing will work. Make sure you are happy with the application ID, title, p12 certificate, and version number - if these values change, you will need to upload a new draft – and it can take anywhere from minutes to hours before Google processes the APK file!

    Important Note for Flash Builder Users: Flash Builder 4.6 will change your application ID every time you switch between a 'release' and 'debug' build. Because the IDs of the uploaded APK and the APK you test with must match, you will either need to commit to using only one type of build during testing, or uploading a new build and waiting a few minutes every time you need to change targets. One solution to mitigate this is to build only for debug until you're ready to publish app, then rebuild and re-upload a new draft at that time. In Flash Builder 4.7, this behavior can be overridden by removing the '.debug' from the 'AppId' box under Run/Debug Configurations Dialog Box (Project Properties > Build Packaging > Run / Debug Settings > Edit.)
  2. Go to http://play.google.com/apps/publish/ to access the Google Play Developer Panel.
  3. Choose '+Add new application' to define your new app.
Figure 1. Add a new application.
Figure 1. Click In-App Products.
 
  1. Enter a title and language for your app, then select 'Upload APK'.
 Figure 2. Uploading a new APK.
Figure 2. Uploading a new APK.
 
  1. Select 'Upload Your First APK', and select the APK file you created in step 1.
  2. From the 'Services & APIs' tab, copy and paste your License Key, and save it for future reference.
Figure 3. Retrieving your license key.
Figure 3. Retrieving your license key.
 
  1. From the 'In-App Products' tab, select 'Add New Product', and enter a name for the first in-app item you'd like to sell.

    If the Item is a Subscription, choose the Subscription button. Otherwise,choose 'Managed'. (Although you may still select 'Unmanaged', the option is deprecated as all Google Play Billing items are now managed.)
Figure 4. Adding a new product.
Figure 4. Adding a new product.
 
  1. Enter the Product ID Title, Description, pricing and language information for your product. Then choose Save, and change the status to Active by choosing the 'Activate' option.
Figure 5. Adding product details.
Figure 5. Adding product details.
 
  1. Repeat the process for each product you'd like to sell. If you'd like to create products that match with the example code, create managed items called 'my_levelpack' and 'my_spell', and a subscription called 'my_subscription'.

 
Preparing for device testing

In order to test In-App Billing, you'll need to update Google Play with your test account address, and possibly make changes to the registered account on your phone.
When you first setup your Android device, you entered a Google/ Gmail Account to use with Google Play – the 'primary account' on your phone. This gmail address needs to be added to the Google Play developer panel in order to test In-app Billing. To add the test email to Google Play:
 
  1. Select the 'Settings' tab from the left.
  2. Select 'Account Details'
  3. Under 'Gmail accounts with testing access', enter the gmail address that is the primary account on the device. You may enter multiple email addresses separated by commas if you wish.
Figure 6. Adding testing accounts.
Figure 6. Adding testing accounts.
 
  1. Unfortunately,Google does not let you 'buy things from yourself'. In other words, if the primary Gmail account is the same as the one you used to sign up for Google Play Developer, you'll need to change the primary account on the device to something else.

    Although many Android devices will let you remove and add accounts, this isn't good enough for Google Play testing- you'll have to factory reset the device. See the documentation for your device's make and model if you need to factory reset the phone.

 
Getting started with the API

While you wait for Google to process your APK, you can start adding code to your application.
Follow these steps to get started:
 
  1. Import the API Classes:
import com.milkmangames.nativeextensions.android.*; import com.milkmangames.nativeextensions.android.events.*;
  1. Initialize the API by calling AndroidIAB.create().You can check the AndroidIAB.isSupported() method first, to ensure the current platform is Android and not an unsupported platform (like iOS or Windows).
It is important that this initialization occurs in the entry point of your application.  If you are using Flex/MXML, this means you must call create() in the initialize() event of the main class (not a View constructor or createComplete callback.) If you are using pure ActionScript, you must call create() inside the Constructor function of the Document Class. If you are using timeline code in Flash, call this once at the beginning of Frame 1.
 
if (AndroidIAB.isSupported()) { AndroidIAB.create(); }
  1. Call the AndroidIAB.androidIAB.startBillingService("YOUR_PUBLIC_KEY_HERE") method to begin interactions with Android's In-App Billing server. Use the public key you retrieved earlier in the section Building the Application and Uploading the Draft to Google Play, Step 6.

    If the current device will not support In-App Billing (because it doesn't have Google Play, for instance), you'll receive the AndroidBillingEvent.SERVICE_NOT_SUPPORTED event. Otherwise, when the service is ready, you'll receive the AndroidBillingEvent.SERVICE_READY event; once that happens, you may begin calling the other API methods to make purchases.
// listeners for billing service startup AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.SERVICE_READY,onReady); AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.SERVICE_NOT_SUPPORTED, onUnsupported); // start the service AndroidIAB.androidIAB.startBillingService("YOUR_PUBLIC_KEY_HERE"); private function onReady(e:AndroidBillingEvent):void { trace("service now ready- you can now make purchases."); } private function onUnsupported(e:AndroidBillingEvent):void { trace("sorry, in app billing won't work on this phone!"); }

 
Loading the player's inventory

Once you've connected to Google Play, you can request information about the items that the user has previously purchased. It's a good idea to do this as soon as your app starts, in case the user has installed the app on a new device, had an item refunded, or their inventory has otherwise changed.
 
  1. Add event listeners for AndroidBillingEvent.INVENTORY_LOADED and AndroidBillingErrorEvent.INVENTORY_LOAD_FAILED. When the INVENTORY_LOADED event is dispatched, its 'purchases' property will be populated with a vector array of AndroidPurchase objects, representing the purchases the user has previously made.

    The LOAD_INVENTORY_FAILED is dispatched when an error occurs attempting to load the inventory. Because it is an error event, you should listen for it even if you don't plan to do anything about the error, to avoid an uncaught exception in your code:
// listen for inventory events AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.INVENTORY_LOADED, onInventoryLoaded); AndroidIAB.androidIAB.addEventListener(AndroidBillingErrorEvent.LOAD_INVENTORY_FAILED, onInventoryFailed); function onInventoryLoaded(e:AndroidBillingEvent):void { for each(var purchase:AndroidPurchase in e.purchases) { trace("You own the item:"+purchase.itemId); // this is where you'd update the state of your app to reflect ownership of the item } } function onInventoryFailed(e:AndroidBillingErrorEvent):void { trace("Something went wrong loading inventory: "+e.text); }
  1. To start the inventory request, call AndroidIAB.androidIAB.loadPlayerInventory():
// load the player's current inventory AndroidIAB.androidIAB.loadPlayerInventory();

 
Loading details about purchasable items

In addition to loading the list of items the player already owns, you may wish to load details about items your app offers for sale, such as title, description, and price.
 
  1. Add event listeners for AndroidBillingEvent.ITEM_DETAILS_LOADED and AndroidBillingErrorEvent.ITEM_DETAILS_FAILED. When the ITEM_DETAILS_LOADED event is dispatched, its itemDetails property will be populated with a vector array of AndroidItemDetails objects, representing the details about items available in your app's store.

    The ITEM_DETAILS_FAILED is dispatched when an error occurs attempting to load the item details. Because it is an error event, you should listen for it even if you don't plan to do anything about the error, to avoid an uncaught exception in your code:
// listen for inventory events AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.ITEM_DETAILS_LOADED, onItemDetails); AndroidIAB.androidIAB.addEventListener(AndroidBillingErrorEvent.ITEM_DETAILS_FAILED, onDetailsFailed); function onItemDetails(e:AndroidBillingEvent):void { for each(var item:AndroidItemDetails in e.itemDetails) { trace("item id:"+item.itemId); trace("title:"+item.title); trace("description:"+item.description); trace("price:"+item.price); } } function onDetailsFailed(e:AndroidBillingErrorEvent):void { trace("Something went wrong loading details: "+e.text); }
  1. To start the details request, pass a Vector array of item ids to the loadItemDetails() function. (The IDs you choose will need to be defined later in the Google Play control panel after you've uploaded your APK):
// load info about the items for sale var allItemIds:Vector.<String>=new <String>["my_spell", "my_subscription", "my_levelpack"]; AndroidIAB.androidIAB.loadItemDetails(allItemIds);

 
Making purchases

  1. First, add event listeners for AndroidBillingEvent.PURCHASE_SUCCEEDED and AndroidBillingErrorEvent.PURCHASE_FAILED:
// listen for purchase events AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.PURCHASE_SUCCEEDED, onPurchaseSuccess); AndroidIAB.androidIAB.addEventListener(AndroidBillingErrorEvent.PURCHASE_FAILED, onPurchaseFailed);
  1. When PURCHASE_SUCCEEDED is dispatched, its purchases property will be a vector array containingan AndroidPurchase object for the item that was bought.When this event fires, you can call loadPlayerInventory() again to update the list of items the player now owns. If something goes wrong,PURCHASE_FAILED will be dispatched instead:
function onPurchaseSuccess(e:AndroidBillingEvent):void { var purchase:AndroidPurchase=e.purchases[0]; trace("you purchased the item "+purchase.itemId); AndroidIAB.androidIAB.loadPlayerInventory(); } function onPurchaseFailed(e:AndroidBillingErrorEvent):void { trace("Something went wrong with the purchase of "+e.itemId+": "+e.text); }
  1. The extension provides a number of functions for testing purchase event responses with fake items that you have not registered in Google Play. The following example illustrates how to initiate such a fake purchase:
// this will start a purchase dialog and on success callback the PURCHASE_SUCCEEDED event AndroidIAB.androidIAB.testPurchaseItemSuccess(); // this will start a purchase dialog then cause a PURCHASE_FAILED event AndroidIAB.androidIAB.testPurchaseItemCancelled();
  1. To start the purchase process for a real item, call AndroidIAB.androidIAB.purchaseItem(itemId),where itemId is one of the products you registered on theGoogle Play Developer panel.

    Note that for the purchase to work on an unpublished app, the test account mustbe set up properly as described above in Section Preparing for Device Testing. As long as you are using a test account, your credit card will not be charged- make sure that the purchase window includes the phrase "You will not be charged."

    To initiate the purchase of a real item:
AndroidIAB.androidIAB.purchaseItem("your_itemid");
  1. If your item is a Subscription Item, use the purchaseSubscriptionItem(itemId) call instead. Because not all phones will support subscriptions, you should check the areSubscritpionsSupported() method first:
if(AndroidIAB.androidIAB.areSubscriptionsSupported()) { AndroidIAB.androidIAB.purchaseSubscriptionItem("your_itemid"); } else { trace("this device needs a Google Play Update to support subscriptions."); }

 
Consuming items

Some in-app purchases may be treated as permanent upgrades,such as pack of new levels added to the game. For these types of items, the user purchases them one time, and they are then treated as permanently owned.
 
Some games or apps may benefit from a 'consumable' type of item: something that can be purchased, used up, and purchased again. To implement such an item, implement the consumption flow as described below:
 
  1. Add event listeners for AndroidBillingEvent.CONSUME_SUCCEEDED and AndroidBillingErrorEvent.CONSUME_FAILED. When the CONSUME_SUCCEEDED event is dispatched, the item has been removed from the player's inventory and can be purchased again, and you should call loadPlayerInventory() again to update the state of the player's inventory.

    The CONSUME_FAILED event is dispatched when an error occurs attempting to consume an item. Because it is an error event, you should listen for it even if you don't plan to do anything about the error, to avoid an uncaught exception in your code:
// listen for consumption events AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.CONSUME_SUCCEEDED, onItemConsumed); AndroidIAB.androidIAB.addEventListener(AndroidBillingErrorEvent.CONSUME_FAILED, onConsumeFailed); function onItemConsumed(e:AndroidBillingEvent):void { trace("you consumed the item "+e.itemId); AndroidIAB.androidIAB.loadPlayerInventory(); } function onConsumeFailed(e:AndroidBillingErrorEvent):void { trace("Something went wrong consuming "+e.itemId+": "+e.text); }
  1. To start the consume request, pass the item's id to the consumeItem() method. (Note that you cannot consume item unless you've previously called loadPlayerInventory() and the item is present):
// consume an item AndroidIAB.androidIAB.consumeItem("my_spell");

 
Building and troubleshooting your app

If you're using Flash Builder4.6 or later, or Flash Professional CS6 or later, and have added the In-AppBilling for Android extension library as described above, then you can compile as you usually do directly from the IDE. If not and you are building your appwith the extension from the command line, then you'll need to specify thedirectory containing the com.milkmangames.extensions.AndroidIAB.ane file.
 
Here is an example build command line:
 
[PATH_TO_AIR_SDK]\bin\adt -package -target apk-debug -storetype pkcs12 -keystore [YOUR_KEYSTORE_FILE] -storepass [YOUR_PASSWORD] anesample.apk app.xml anesample.swf -extdir [DIRECTORY_CONTAINING_ANE_FILE]
If your app is not receiving events as expected, try these tips:
 
  • Make sure you've saved a draft of the application to the Android Market Developer Website as described in Building the Application and Uploading a Draft to Google Play.
  • Make sure you've updated your application descriptor file as described in Updating your application descriptor file.
  • Make sure the Google email address associated with your device is a Registered Developer Email or a Test Account Email as described in Preparing for Device Testing.
  • If you're testing the IAB example application as is, make sure that you've created the In-App Product IDs that it uses: a managed product named my_levelpack and an unmanaged one named my_spell.See Building the Application and Uploading a Draft to Google Play for information on how to set up products.
  • If you're using a subscription product, make sure you're using the purchaseSubscriptionItem() method.
  • Google can take anywhere from an hour to a day to update its servers after you upload a new draft APK or change a product; wait at least an hour and try again.
    • If you want to implement purchase verification on your own server:
      • The AndroidPurchase object contains the properties itemId, developerPayload, orderId, jsonData, signature, purchaseTime, and purchaseToken. You can pass all or a subset of this data back to your server for verification. Refer to Google's latest documentation for information on how to validate a purchase using your key.
    • If your application appears to stop responding after calling certain functions:
      • If you don't have a debugger attached, and you're doing something that's causing an ErrorEvent, execution will halt but you may not notice it. Always add event listeners of the type AndroidBillingErrorEvent.
      • If you've done that, look carefully at your function signature, and make sure the type is e:AndroidBillingErrorEvent and not e:AndroidBillingEvent.

 
Where to go from here

Now that you have the In-App Billing Extension for Android up and running, you may want to explore the ActionScript 3 documentation, read about Using the iOS In-App Purchase native extension for Adobe AIR, or check out the other tools from available from Milkman Games.