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

Taking your users' money!

Taking your users' money!

Version 2 of this presentation at Droidcon Berlin.

Now covering Google Play Billing Library version 2.

30966c6e1a52faf6b287b59a01195938?s=128

Kai Koenig

July 03, 2019
Tweet

Transcript

  1. TAKING YOUR USERS’ MONEY IN-APP BILLING FROM START TO BEST

    PRACTICES KAI KOENIG (@AGENTK)
  2. HELLO HELLO, MY NAME IS KAI Software Engineer in the

    Web and Android space. Work: Android & Java, Kotlin, JS, CFML, Flutter Non-work: Aviation & flying small aircraft, Nintendo video games, Chickens, Linux Twitter: @AgentK He/Him
  3. AGENDA ▸ Google Play In-app Billing API v3 ▸ Google

    Play Billing Library ▸ Products and subscriptions ▸ Integration concerns ▸ Testing and 3rd-party libraries OVERVIEW
  4. WHY THIS TALK? https://www.flickr.com/photos/tschiae/8080742303/ ?

  5. https://www.flickr.com/photos/designsbykari/5567044644/

  6. APP PURCHASE ADMOB IN-APP PRODUCTS

  7. BUT THERE’S MORE ▸ In-app billing is a “niche” API.

    ▸ It has some documentation and functional issues. ▸ Building and integrating a solution with existing systems can be surprisingly quirky. WHY THIS TALK?
  8. GOOGLE PLAY IN-APP BILLING API V3 https://www.flickr.com/photos/ 134001752@N05/32948793381

  9. NON-PHYSICAL GOODS IN APPS ▸ Google Play in-app billing GOOGLE

    PLAY BILLING (from https://developers.google.com/pay/api/faq)
  10. OVERVIEW ▸ Service that lets you sell digital content on

    Android: ▸ Access to features in an app ▸ Access to virtual products or virtual currency ▸ One-off purchases (consumable and non-consumable) ▸ Recurring subscriptions ▸ Can be accessed via IPC/AIDL or Google Play Billing library (GPBL) GOOGLE PLAY BILLING
  11. GOOGLE PLAY BILLING LIBRARY https://www.flickr.com/photos/vpickering/6488181673/

  12. Client Server APP Google Play Google Play Server G P

    B L Backend application Google Play Developer API
  13. FROM 30,000 FEET (I) ▸ In your app: Google Play

    Billing library ▸ Communicates with Google Play Store app and Play Store infrastructure ▸ Fully asynchronous ▸ Retrieve products, subscriptions, prices etc ▸ Check previous purchases ▸ Buy and consume products, acknowledge purchases, start subscriptions ▸ Centered around BillingClient and PurchasesUpdatedListener GOOGLE PLAY BILLING
  14. FROM 30,000 FEET (II) ▸ On the back end: Google

    Play Developer API ▸ Implement an integration between your server and the REST API ▸ Core features: ▸ Subscriptions and Google Play Billing API: Verify product purchases or subscriptions ▸ Real-time notifications: Notify back end when customers change or cancel subscriptions GOOGLE PLAY BILLING
  15. SETUP GOOGLE PLAY BILLING dependencies { ... implementation 'com.android.billingclient:billing:2.0.1' }

    private var billingClient: BillingClient billingClient = BillingClient .newBuilder(context) .setListener(this) .build() <uses-permission android:name="com.android.vending.BILLING" />
  16. CONNECTION GOOGLE PLAY BILLING billingClient.startConnection(object: BillingClientStateListener { override fun onBillingSetupFinished(billingResult:

    BillingResult) { if (billingResult.responseCode == BillingResponse.OK) { // Ready to go } } override fun onBillingServiceDisconnected() { // We lost connection } })
  17. GOTCHAS ▸ The this-reference in .setListener(this) in the setup process

    points to the PurchasesUpdatedListener interface. ▸ Make sure you override onBillingServiceDisconnected and do something in there - otherwise you can end up with weird errors (often while Google Play or Play Services get updated). GOOGLE PLAY BILLING
  18. PRODUCTS AND SUBSCRIPTIONS https://www.flickr.com/photos/tschiae/8080742303/ https://www.flickr.com/photos/krazykory/346321042/

  19. GENERAL ▸ All in-app purchase options are managed in the

    Google Play Console: ▸ Title and Description ▸ Product ID (in GPBL: SKU - Stock Keeping Unit) ▸ Price and Default Price ▸ 1-to-many relationship between app and in-app purchase options ▸ Watch out for complexities around international pricing or sets of apps with similar/identical prices. PRODUCTS AND SUBSCRIPTIONS
  20. PRODUCTS ▸ One-time product: ▸ Single, non-recurring charge to a

    payment method ▸ “Managed product” in Google Play Console ▸ Rewarded product: ▸ New since GPBL 1.2.1 (mid-March 2019) ▸ In-app product requiring user to watch a video ad (->AdMob) ▸ Type: INAPP in Google Play Billing library PRODUCTS AND SUBSCRIPTIONS
  21. SUBSCRIPTIONS ▸ In-app product with recurring billing: ▸ Weekly ▸

    Monthly (1, 3 and 6 months) ▸ Annually ▸ Free trial and introduction pricing ▸ Since GPBL 1.2 (October 2018) support for a pricing change flow ▸ Type: SUBS in Google Play Billing library PRODUCTS AND SUBSCRIPTIONS
  22. None
  23. GETTING A LIST OF PRODUCTS PRODUCTS AND SUBSCRIPTIONS val skuList

    = ArrayList<String>() skuList.add("SKU1") skuList.add("SKU2") val params = SkuDetailsParams.newBuilder() params.setSkusList(skuList) .setType(SkuType.INAPP) billingClient.querySkuDetailsAsync(params.build(), { BillingResult, skuDetailsList -> // Deal with the result })
  24. ANYTHING WEIRD HERE? ▸ We had to specify a list

    of SKUs. ▸ We had to specify what product type we want to query. ▸ There is NO way to get a list of all your products or products across multiple types. Your app needs to know the SKU identifiers. ▸ Where and how to store them? ▸ What are the implication on your system’s resilience? PRODUCTS AND SUBSCRIPTIONS
  25. THE SKUDETAILS OBJECT PRODUCTS AND SUBSCRIPTIONS getDescription() getPrice() €3.99 getPriceAmountMicros()

    3990000 getPriceCurrencyCode() ISO4217 getSKU() getTitle() getType() INAPP / SUBS getIntroductoryPrice() getIntroductoryPriceCycles() getIntroductoryPricePeriod() ISO8601 getFreeTrialPeriod() ISO8601 getSubscriptionPeriod() ISO8601 isRewarded()
  26. PURCHASE FLOW (I) ▸ GBPL uses the Google Play app

    to drive the purchase flow. ▸ Depending on version of Android, Google Play app and Play Services, certain features might not be available. ▸ BillingClient.isFeatureSupported() PRODUCTS AND SUBSCRIPTIONS
  27. PURCHASE FLOW (II) PRODUCTS AND SUBSCRIPTIONS val flowParams = BillingFlowParams.newBuilder()

    .setSkuDetails(skuDetails) .build() val responseCode = billingClient.launchBillingFlow(flowParams) ▸ Response gets delivered to onPurchasesUpdated() in the PurchasesUpdatedListener.
  28. PURCHASE FLOW (OLDER STLYE) PRODUCTS AND SUBSCRIPTIONS

  29. PURCHASE FLOW (NEWER STYLE) PRODUCTS AND SUBSCRIPTIONS

  30. ACKNOWLEDGING PURCHASES ▸ Since GPBL 2.0 you have to acknowledge

    a purchase (3 days) ▸ Consumable products: BillingClient.consumeAsync() ▸ Non-consumable products: BillingClient.acknowledgePurchase() ▸ Also see: Pending Purchases PRODUCTS AND SUBSCRIPTIONS
  31. SAMPLE GOTCHAS PRODUCTS AND SUBSCRIPTIONS

  32. INTEGRATION CONCERNS https://www.clipartmax.com/middle/ m2i8i8K9i8G6G6A0_system-integration-system- integration-clipart/

  33. VERIFICATION OF A PURCHASE ▸ When a purchase/subscription was successful,

    you get a purchase token. ▸ Google Play Developer API: ▸ Pass token and customer ID to your own backend ▸ From there, call out to REST API and make sure the token is valid and a purchase/subscription exists. ▸ Inside of the app: ▸ Check signature of original JSON payload in onPurchasesUpdated() INTEGRATION CONCERNS
  34. UPDATE YOUR OWN RECORDS ▸ Use case: ▸ App has

    its own member/customer management backend which tracks purchases from other sources as well. ▸ Needs to be kept in sync with in-app purchases. ▸ Similar to verification, call out to own backend. ▸ Additionally make sure to track the order ID for potential refunds. INTEGRATION CONCERNS
  35. CONSUMPTION AND RESTORING PURCHASES (I) ▸ A product can usually

    only be purchased once per Google Play account. ▸ Unfortunately there are use cases where this concept doesn’t work. ▸ First approach: ▸ Consume purchase with BillingClient.consumeAsync() ▸ Callback via onConsumeResponse() in ConsumeResponseListener INTEGRATION CONCERNS
  36. CONSUMPTION AND RESTORING PURCHASES (II) ▸ Problem: ▸ Products with

    a successful consumeAsync() callback sometimes still show up in BillingClient.queryPurchases() & .queryPurchaseHistoryAsync() ▸ Edge cases around caching on the API side ▸ Edge cases with apps ANR’ing or crashing and calls not being finished ▸ Real solution (again): ▸ Use the server side API to check if a product really has been consumed. INTEGRATION CONCERNS
  37. SUBSCRIPTION CANCELLATIONS ▸ Use case: ▸ Customers can cancel subscriptions

    in the Google Play app. ▸ Needs to be communicated to app to restrict access to features. ▸ BillingClient.queryPurchaseHistoryAsync() will work initially: ▸ From first renewal, you won’t get the renewal date stamp, but only the original subscription date. ▸ Better use Google Play Developer API real-time notifications from the start. INTEGRATION CONCERNS
  38. REAL-TIME NOTIFICATIONS ▸ RT Notifications provide real-time information on state

    changes of subscriptions. INTEGRATION CONCERNS GCP Pub/Sub Backend application Google Play Developer API
  39. PRICING CHANGES ▸ Up to version 1.1, Google Play Billing

    library didn’t support pricing changes. ▸ Solution: code SKUs in parseable ways and re-create the product with a new SKU INTEGRATION CONCERNS gold_1m_v_1 gold_1m_v_2 gold_1m_v_3 … ▸ GPBL 1.2+ has a UI flow for pricing changes: BillingClient.launchPriceChangeConfirmationFlow()
  40. TESTING AND 3RD PARTY LIBRARIES https://www.flickr.com/photos/tschiae/8080742303/ https://www.flickr.com/photos/37149125@N04/10170683255

  41. TESTING ▸ Testing has changed over time: ▸ Unpublished/local build

    with draft Google Play products ▸ Unpublished/local build with static product SKUs to trigger responses ▸ Published build with actual Google Play products (closed testing track) ▸ Fiddling with user accounts ▸ Only physical devices ▸ “Licensed” testers TESTING AND 3RD PARTY LIBRARIES
  42. TESTING SUBSCRIPTIONS TESTING AND 3RD PARTY LIBRARIES

  43. GOTCHAS ▸ The APK you uploaded needs to match the

    one you’re testing with when it comes to version code, version name and keystore signature. ▸ You can not use your Play Console developer account for testing on the device. TESTING AND 3RD PARTY LIBRARIES
  44. REGISTER (I) ▸ Register is an Android library for easier

    testing of Google Play's In-app Billing. ▸ Register comes with a companion app that acts as a mock billing server. TESTING AND 3RD PARTY LIBRARIES if (shouldUseTest) { googleServiceProvider = new GoogleServiceProviderTesting(); } else { googleServiceProvider = new GoogleServiceProviderImpl(); }
  45. REGISTER (II) TESTING AND 3RD PARTY LIBRARIES ▸ Great approach

    - doesn’t properly support GPBL yet though. ▸ There’s been recent activity towards a 1.0.0 release.
  46. BILLINGX TESTING AND 3RD PARTY LIBRARIES ▸ Extension for Google

    Play Billing Library to do fake purchases in debug builds. ▸ BillingX doesn’t have all the configuration bells and whistles of Register at this stage: ▸ No config activity ▸ Product consumption was just recently added debugImplementation 'com.pixiteapps.billingx:billingx:0.8.2' releaseImplementation 'com.android.billingclient:billing:1.0'
  47. BILLINGX - RELEASE TESTING AND 3RD PARTY LIBRARIES object BillingClientFactory

    { fun createBillingClient( activity: Activity, updateListener: PurchasesUpdatedListener): BillingClient { return BillingClient .newBuilder(activity) .setListener(updateListener) .build() } }
  48. BILLINGX - DEBUG TESTING AND 3RD PARTY LIBRARIES object BillingClientFactory

    { fun createBillingClient( activity: Activity, updateListener: PurchasesUpdatedListener): BillingClient { return DebugBillingClient( activity = activity, backgroundExecutor = Executors.diskIO, purchasesUpdatedListener = updateListener ) } }
  49. FINAL THOUGHTS https://www.flickr.com/photos/chrispiascik/4054331891

  50. TRANSACTION FEES ▸ In-app products: 70% (you) / 30% (Google)

    ▸ In-app subscriptions after 12 months of retention: 85% (you) / 15% (Google) FINAL THOUGHTS
  51. GOOD ▸ Generally in-app billing is a reasonably easy-to-use API.

    ▸ Google Play Billing Library is a huge improvement over the old AIDL-based approach. ▸ Active development and progression, albeit slow. FINAL THOUGHTS
  52. PROBLEMATIC ▸ Inconsistent documentation ▸ There are functional gaps in

    the API. ▸ Samples are… challenging ▸ Don’t fall for the implied rhetoric of not needing a backend. ▸ Testing is a nightmare (3rd party libs help a lot though). FINAL THOUGHTS
  53. OTHER THINGS RESOURCES (I) ▸ Google Play Billing library release

    notes: https://developer.android.com/google/play/billing/billing_library_releases_notes.html ▸ Google Play Billing library developer docs: https://developer.android.com/google/play/billing/billing_overview ▸ Google Play Developer API: https://developers.google.com/android-publisher/ ▸ Google Play Developer API for creating/editing in-app products: https://developers.google.com/android-publisher/api-ref/inappproducts ▸ Gradle Play Publisher: https://github.com/Triple-T/gradle-play-publisher
  54. OTHER THINGS RESOURCES (II) ▸ Various in-app-billing sample apps: https://github.com/googlesamples/android-play-billing

    ▸ Google Play Developer API for purchases and subscriptions: https://developers.google.com/android-publisher/api-ref/purchases/products https://developers.google.com/android-publisher/api-ref/purchases/subscriptions ▸ Google Play Billing Testing documentation: https://developer.android.com/google/play/billing/billing_testing.html ▸ NY Times Register: https://github.com/NYTimes/Register ▸ BillingX: https://github.com/pixiteapps/billingx
  55. OTHER THINGS GET IN TOUCH Kai Koenig Email: kai@ventego-creative.co.nz Work:

    http://www.ventego-creative.co.nz Twitter: @AgentK Slides: https://speakerdeck.com/therealagentk (previously: http://www.slideshare.com/agentk)