Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Monetizing Android apps on the Play Store

Monetizing Android apps on the Play Store

Talk given at DroidCon NYC 2015 and AnDevCon Boston 2015 about integrating in-app billing in Android apps

Yash Prabhu

August 01, 2015

More Decks by Yash Prabhu

Other Decks in Technology


  1. Monetizing Android apps on the Play Store Yash Prabhu @yashvprabhu

    | @dramafever Slides https://goo.gl/1p9k1r Image credit: Stock Android lollipop wallpaper
  2. Security Google Play Developer API Revenue Models Product Types Purchase

    Workflow In-app Billing v3 API Testing Image credit: Material icons
  3. Digital & Physical Goods • Freemium - 30% ◦ In-app

    products ◦ Subscription • Paid • AdMob • Android Pay Digital Goods Physical Goods
  4. Non-Consumable • Can be purchased only once • Permanent benefit

    Managed: For One time purchases Consumable • Can be purchased multiple times • Temporary benefit Image credit: Material icons
  5. Subscriptions - For automated, recurring billing • Weekly, monthly, annual,

    seasonal • Free trials - 7 to 30 days • Manual renewal • Upgrade/downgrade • Deferred Billing
  6. Purchase response Response data GOOGLE PLAY DEVELOPER API YOUR SERVER

    Purchase request Purchase response GOOGLE PLAY APP ANDROID CLIENT APP Purchase response GOOGLE PLAY SERVER
  7. In-app billing setup 1. Set up Merchant account 2. Integrate

    in-app billing v3 API 3. Define in-app products 4. Provision premium content 5. Profit!
  8. Set up Merchant Account 1. Go to https://play.google.com/apps/publish/ 2. Open

    Financial reports on the side bar 3. Click Setup a Merchant Account now Step 1
  9. Set up In-app billing v3 • Go to sdk/extras/google/play_billing •

    Copy into your project ◦ IInAppBillingService.aidl ◦ All Java files in trivialdrivesample/util • Add billing permission into your manifest <uses-permission android:name= "com.android.vending.BILLING" /> 1Step 2
  10. Your in- app billing app Google Play App isBillingSupported() Supported/Not

    Supported getPurchases() Bundle(purchase info ....) getSkuDetails() Bundle(response code, sku info) getBuyIntent() Bundle(response code, buy intent) startIntentSenderForResult() Bundle(response code, purchase data, signature)
  11. Is billing supported? public void onServiceConnected(ComponentName name, IBinder service) {

    mService = IInAppBillingService.Stub.asInterface(service); int response = mService.isBillingSupported(3, packageName, itemType); if (response == BILLING_RESPONSE_RESULT_OK) { // billing is supported } else { // billing is not supported } }
  12. Query user’s owned products Bundle ownedItems = mService.getPurchases(3, packageName, itemType,

    continueToken); itemType => “inapp” || “subs” continueToken => retrieve next set of owned purchases
  13. Query in-app product details Bundle skuDetails = mService.getSkuDetails(3, packageName, itemType,

    querySkus); itemType => “inapp” || “subs” querySkus => Bundle of all owned skus
  14. When user wants to purchase public void launchPurchaseFlow(Activity act, String

    sku, String itemType, int requestCode, OnIabPurchaseFinishedListener listener, String extraData) { .... Bundle buyIntentBundle = mService.getBuyIntent(3, packageName, sku, itemType, extraData); .... }
  15. Get purchase information public boolean handleActivityResult(int requestCode, int resultCode, Intent

    data) { int responseCode = getResponseCodeFromIntent(data); String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA); String dataSignature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE); return true; }
  16. Consume a purchase void consume(Purchase itemInfo) throws IabException { String

    token = itemInfo.getToken(); String sku = itemInfo.getSku(); int response = mService.consumePurchase(3, packageName, token); if (response == BILLING_RESPONSE_RESULT_OK) { // sku consumed successfully } }
  17. Quick Recap • isBillingSupported? • getPurchases() • getSkuDetails() • getBuyIntent()

    • handleActivityResult() • if consumable purchase is successful, consume() On startup On purchase After purchase
  18. Purchase data { "orderId": "1299911111111111.145333335334137..0", "packageName": "com.sample.app", "productId": "test_inapp_upgrade", "purchaseTime":

    1384834368656, "purchaseState": 0, "developerPayload": "abcdef", "purchaseToken": "fdgdghdjdp86dg", "autoRenewing":true }
  19. Testing • Add licensed test users to Google Play developer

    console • Reserved product ids • No charges • • Regular users who can download your app from the Play Store • Real product ids • Actual charges Similar: Publish on Alpha, Beta or Production channels Test Purchases Regular Purchases
  20. Testing with reserved product IDs • Install signed apk on

    a test device. No emulators! • Sign into device with your developer account • Google Play version 2.3.4+ or MyApps app 5.0.12+ • Android 2.2+ • Run your app and purchase reserved product ID
  21. Testing with actual product IDs • No draft apks: Upload

    signed apk to alpha/beta channel • Add a real managed product to Developer Console • Install signed apk on a test device. No emulators! • Google Play version 2.3.4+ or MyApps app 5.0.12+ • Android 2.2+ • Purchase the real product with a real credit card • Factory reset device for same product purchase!
  22. Testing subscriptions before Feb 2015 • There was no sandbox!

    • Create a test $0.99 monthly subscription product • Purchase product with real credit card • Refund & cancel order on the Google Wallet console • Wait till end of subscription period to retest or factory reset device! https://www.emojibase.com/emoji/1f622/cryingface
  23. Testing subscriptions after Feb 2015 • Use android.test.purchased reserved product

    • Buy the product • Wait for 1 day to retest subscription Image credit
  24. Security • Obfuscate code using Proguard -keep class com.android.vending.billing.** •

    Protect unlocked/premium content • Protect your Google Play Public Key • Modify sample application code • Use developer payload to uniquely identify user • Signature verification on your client and server
  25. Decode base64 Public Key & verify signature public static boolean

    verifyPurchase(String base64PublicKey, String purchaseData, String signature) { boolean verified = false; if (!TextUtils.isEmpty(signature)) { PublicKey key = Security.generatePublicKey(base64PublicKey); verified = Security.verify(key, purchaseData, signature); } return true; }
  26. Purchase response Response data GOOGLE PLAY DEVELOPER API YOUR SERVER

    Purchase request Purchase response GOOGLE PLAY APP ANDROID CLIENT APP Purchase response GOOGLE PLAY SERVER
  27. Why use Google Play Developer API? • 200,000 queries per

    day for free! • Publishing API • Subscriptions & In-app purchases API
  28. Setting up Google Play Developer API 1. Set up an

    APIs Console Project https://console.developers.google.com/ 2. Create an OAuth 2.0 Client ID 3. Generate a refresh token & access tokens 4. Access the API
  29. Purchases.products.get request Checks the purchase and consumption status of an

    inapp item. GET https://www.googleapis.com/androidpublisher/v2/app lications/packageName/purchases/products/productI d/tokens/token
  30. Purchases.subscriptions.get request Checks validity & expiration of a user's subscription

    purchase GET https://www.googleapis.com/androidpublisher/v2/app lications/packageName/purchases/subscriptions/subs criptionId/tokens/token
  31. Google API Client libraries • Easier to set up authentication

    and authorization • Reduces OAuth 2.0 code • Featured: Java, Python, .NET, PHP, Javascript • Early-stage: Go, Dart, Ruby, Node-js, Objective-C • https://developers.google.com/api-client-library/
  32. References • Google Play In-app Billing • Training: Using Google

    Play to Distribute and Monetize • Video: In-app Billing Version 3 (Google I/O 2013) • Using OAuth 2.0 to access Google Play APIs • Google API client libraries