$30 off During Our Annual Pro Sale. View Details »

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
Tweet

More Decks by Yash Prabhu

Other Decks in Technology

Transcript

  1. Monetizing Android apps
    on the Play Store
    Yash Prabhu
    @yashvprabhu | @dramafever
    Slides https://goo.gl/1p9k1r
    Image credit: Stock Android lollipop wallpaper

    View Slide

  2. Why are we here?
    Image credit

    View Slide

  3. 7 Things we will learn
    today

    View Slide

  4. Security
    Google Play
    Developer API
    Revenue Models
    Product Types
    Purchase
    Workflow
    In-app Billing v3 API
    Testing
    Image credit: Material icons

    View Slide

  5. Revenue Models
    One

    View Slide

  6. Digital & Physical Goods
    ● Freemium - 30%
    ○ In-app products
    ○ Subscription
    ● Paid
    ● AdMob
    ● Android Pay
    Digital Goods Physical Goods

    View Slide

  7. Product Types
    Two

    View Slide

  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

    View Slide

  9. Subscriptions - For automated, recurring billing
    ● Weekly, monthly, annual, seasonal
    ● Free trials - 7 to 30 days
    ● Manual renewal
    ● Upgrade/downgrade
    ● Deferred Billing

    View Slide

  10. View Slide

  11. Purchase Workflow
    Three

    View Slide

  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

    View Slide

  13. In-app Billing v3 API
    Client side workflow
    Four

    View Slide

  14. Image credit

    View Slide

  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!

    View Slide

  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

    View Slide

  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
    android:name= "com.android.vending.BILLING" />
    1Step 2

    View Slide

  18. Copy your license key into IabHelper.java
    Iab => In-app billing

    View Slide

  19. Upload alpha apk. Hit Publish!

    View Slide

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

    View Slide

  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)

    View Slide

  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
    }
    }

    View Slide

  23. Query user’s owned products
    Bundle ownedItems =
    mService.getPurchases(3, packageName, itemType, continueToken);
    itemType => “inapp” || “subs”
    continueToken => retrieve next set of owned purchases

    View Slide

  24. Query in-app product details
    Bundle skuDetails =
    mService.getSkuDetails(3, packageName, itemType, querySkus);
    itemType => “inapp” || “subs”
    querySkus => Bundle of all owned skus

    View Slide

  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);
    ....
    }

    View Slide

  26. App launches the pending intent
    PendingIntent pendingIntent =
    buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT);
    activity.startIntentSenderForResult(
    pendingIntent.getIntentSender(), requestCode,
    new Intent(), flagsMask, flagsValues, extraFlags);

    View Slide

  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;
    }

    View Slide

  28. Google
    Play
    App
    Your in-
    app
    billing
    app
    getPurchases()
    Bundle(purchase info ....)
    consumePurchase()
    Success/Failure

    View Slide

  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
    }
    }

    View Slide

  30. Quick Recap
    ● isBillingSupported?
    ● getPurchases()
    ● getSkuDetails()
    ● getBuyIntent()
    ● handleActivityResult()
    ● if consumable
    purchase is successful,
    consume()
    On startup
    On purchase
    After purchase

    View Slide

  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 }

    View Slide

  32. Signature & Response code
    Signature: jHCzy6MGITNtOuF0nfYyiEyGw==
    Response codes
    0 - Purchased
    1 - Canceled
    2 - Refunded

    View Slide

  33. Testing
    Client side workflow
    Five

    View Slide

  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

    View Slide

  35. View Slide

  36. Reserved product IDs
    ● android.test.purchased
    ● android.test.canceled
    ● android.test.refunded
    ● android.test.item_unavailable

    View Slide

  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

    View Slide

  38. View Slide

  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!

    View Slide

  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

    View Slide

  41. Testing subscriptions after Feb 2015
    ● Use android.test.purchased reserved
    product
    ● Buy the product
    ● Wait for 1 day to retest subscription
    Image credit

    View Slide

  42. Valid subscription product purchase!

    View Slide

  43. Common errors

    View Slide

  44. View Slide

  45. Security
    Client side workflow
    Six

    View Slide

  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

    View Slide

  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;
    }

    View Slide

  48. Google Play Developer API
    Server side workflow
    Seven

    View Slide

  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

    View Slide

  50. Why use Google Play Developer API?
    ● 200,000 queries per day for free!
    ● Publishing API
    ● Subscriptions & In-app purchases API

    View Slide

  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

    View Slide

  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

    View Slide

  53. Purchases.products.get response
    {
    "kind": "androidpublisher#productPurchase",
    "purchaseTimeMillis": long,
    "purchaseState": integer,
    "consumptionState": integer,
    "developerPayload": string
    }

    View Slide

  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

    View Slide

  55. Purchases.subscriptions.get response
    {
    "kind": "androidpublisher#subscriptionPurchase",
    "startTimeMillis": long,
    "expiryTimeMillis": long,
    "autoRenewing": boolean
    }

    View Slide

  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/

    View Slide

  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

    View Slide

  58. Q&A
    Yash Prabhu
    @yashvprabhu
    Slides https://goo.gl/1p9k1r
    Work at DramaFever http://goo.gl/gWUM5U

    View Slide