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

00bc3e6ec35c62fabef044e492070c29?s=128

Yash Prabhu

August 01, 2015
Tweet

Transcript

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

    | @dramafever Slides https://goo.gl/1p9k1r Image credit: Stock Android lollipop wallpaper
  2. Why are we here? Image credit

  3. 7 Things we will learn today

  4. Security Google Play Developer API Revenue Models Product Types Purchase

    Workflow In-app Billing v3 API Testing Image credit: Material icons
  5. Revenue Models One

  6. Digital & Physical Goods • Freemium - 30% ◦ In-app

    products ◦ Subscription • Paid • AdMob • Android Pay Digital Goods Physical Goods
  7. Product Types Two

  8. 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
  9. Subscriptions - For automated, recurring billing • Weekly, monthly, annual,

    seasonal • Free trials - 7 to 30 days • Manual renewal • Upgrade/downgrade • Deferred Billing
  10. None
  11. Purchase Workflow Three

  12. 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
  13. In-app Billing v3 API Client side workflow Four

  14. Image credit

  15. 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!
  16. 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
  17. 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
  18. Copy your license key into IabHelper.java Iab => In-app billing

  19. Upload alpha apk. Hit Publish!

  20. Set up a new product on Developer Console 1Step 3

  21. 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)
  22. 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 } }
  23. Query user’s owned products Bundle ownedItems = mService.getPurchases(3, packageName, itemType,

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

    querySkus); itemType => “inapp” || “subs” querySkus => Bundle of all owned skus
  25. 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); .... }
  26. App launches the pending intent PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT); activity.startIntentSenderForResult(

    pendingIntent.getIntentSender(), requestCode, new Intent(), flagsMask, flagsValues, extraFlags);
  27. 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; }
  28. Google Play App Your in- app billing app getPurchases() Bundle(purchase

    info ....) consumePurchase() Success/Failure
  29. 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 } }
  30. Quick Recap • isBillingSupported? • getPurchases() • getSkuDetails() • getBuyIntent()

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

    1384834368656, "purchaseState": 0, "developerPayload": "abcdef", "purchaseToken": "fdgdghdjdp86dg", "autoRenewing":true }
  32. Signature & Response code Signature: jHCzy6MGITNtOuF0nfYyiEyGw== Response codes 0 -

    Purchased 1 - Canceled 2 - Refunded
  33. Testing Client side workflow Five

  34. 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
  35. None
  36. Reserved product IDs • android.test.purchased • android.test.canceled • android.test.refunded •

    android.test.item_unavailable
  37. 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
  38. None
  39. 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!
  40. 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
  41. Testing subscriptions after Feb 2015 • Use android.test.purchased reserved product

    • Buy the product • Wait for 1 day to retest subscription Image credit
  42. Valid subscription product purchase!

  43. Common errors

  44. None
  45. Security Client side workflow Six

  46. 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
  47. 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; }
  48. Google Play Developer API Server side workflow Seven

  49. 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
  50. Why use Google Play Developer API? • 200,000 queries per

    day for free! • Publishing API • Subscriptions & In-app purchases API
  51. 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
  52. 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
  53. Purchases.products.get response { "kind": "androidpublisher#productPurchase", "purchaseTimeMillis": long, "purchaseState": integer, "consumptionState":

    integer, "developerPayload": string }
  54. 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
  55. Purchases.subscriptions.get response { "kind": "androidpublisher#subscriptionPurchase", "startTimeMillis": long, "expiryTimeMillis": long, "autoRenewing":

    boolean }
  56. 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/
  57. 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
  58. Q&A Yash Prabhu @yashvprabhu Slides https://goo.gl/1p9k1r Work at DramaFever http://goo.gl/gWUM5U