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
▸ It has some documentation and functional issues. ▸ Building and integrating a solution with existing systems can be surprisingly quirky. WHY THIS TALK?
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
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
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
BillingResult) { if (billingResult.responseCode == BillingResponse.OK) { // Ready to go } } override fun onBillingServiceDisconnected() { // We lost connection } })
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
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
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
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
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
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
.setSkuDetails(skuDetails) .build() val responseCode = billingClient.launchBillingFlow(flowParams) ▸ Response gets delivered to onPurchasesUpdated() in the PurchasesUpdatedListener.
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
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
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
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
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
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()
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
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
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(); }
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'
▸ Google Play Billing Library is a huge improvement over the old AIDL-based approach. ▸ Active development and progression, albeit slow. FINAL THOUGHTS
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
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
▸ 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