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.

Kai Koenig

July 03, 2019
Tweet

More Decks by Kai Koenig

Other Decks in Programming

Transcript

  1. 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
  2. AGENDA ▸ Google Play In-app Billing API v3 ▸ Google

    Play Billing Library ▸ Products and subscriptions ▸ Integration concerns ▸ Testing and 3rd-party libraries OVERVIEW
  3. 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?
  4. NON-PHYSICAL GOODS IN APPS ▸ Google Play in-app billing GOOGLE

    PLAY BILLING (from https://developers.google.com/pay/api/faq)
  5. 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
  6. Client Server APP Google Play Google Play Server G P

    B L Backend application Google Play Developer API
  7. 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
  8. 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
  9. 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" />
  10. 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 } })
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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 })
  16. 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
  17. 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()
  18. 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
  19. 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.
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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()
  28. 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
  29. 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
  30. 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(); }
  31. 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.
  32. 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'
  33. BILLINGX - RELEASE TESTING AND 3RD PARTY LIBRARIES object BillingClientFactory

    { fun createBillingClient( activity: Activity, updateListener: PurchasesUpdatedListener): BillingClient { return BillingClient .newBuilder(activity) .setListener(updateListener) .build() } }
  34. 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 ) } }
  35. TRANSACTION FEES ▸ In-app products: 70% (you) / 30% (Google)

    ▸ In-app subscriptions after 12 months of retention: 85% (you) / 15% (Google) FINAL THOUGHTS
  36. 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
  37. 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
  38. 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
  39. 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
  40. OTHER THINGS GET IN TOUCH Kai Koenig Email: [email protected] Work:

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