Google Billing Library Migration

By Casey Idzikowski

Audible Tech
Audible Tech Blog
10 min readOct 17, 2023

--

Cover image. Birds migrating.
Photo by Julia Craice on Unsplash

Recently, Audible’s Android team migrated the in-app Google Play Billing Library from version 4.x to 6.x. This upgrade came with a shift in Google’s in-app product structure that created challenges for us to overcome. In this blog post, we will discuss some Audible-specific migration strategies we employed and our reasons for using them. We will also discuss some challenges we encountered and how we planned for a consistent customer experience. If you’re looking for more specific step-by-step guide on how to migrate, check out Google’s documentation.

As of the writing this blog post, Audible for Android is currently using Google Play Billing in the following countries: United States, Canada, Great Britain/ United Kingdom, Australia, and Japan.

Library Updates

Google Billing Library 5

In May 2022, Google released the Google Play Billing Library version 5 (v5), introducing a new data model for subscription products. In v4 (pictured on the left), subscriptions had a one-to-one relationship with introductory offers, meaning there could only be one offer per subscription product. In the new v5 model (pictured on the right), Google moved towards a one-to-many relationship and introduced a new concept of a “base plan.”

An infographic showing the difference between the v4 and v5 subscription models.
V4 (left) vs. V5 (right) subscription models (Source)

The multi-tiered structure can be broken down into three parts:

  1. Subscription — the subscription represents the benefits the customer will receive in-app (e.g., Audible PremiumPlus subscription).
  2. Base plan — the base plan (newly introduced in v5) represents the billing period frequency (e.g., monthly, annual)
  3. Offer — an introductory discount for the customer at purchase (subject to eligibility rules).

Google also introduced a new eligibility setting for offers (free trial, discounts, etc.) called “developer-determined.” With developer-determined eligibility, the developer is given complete freedom to decide their own eligibility rules and criteria.

To process the new subscription capabilities, Google introduced a new purchases.subscriptionsv2 developer API endpoint that can be integrated with the backend service aspect of the Google Play Billing system. Both the v2 and original purchases.subscription endpoints are used to get the subscription product information for a given purchase; however, the v2 endpoint contains new fields like offerId and basePlanId.

Google also made changes to the way subscription products are managed on the Google Play Console, automatically converting the “old” version 4 (v4) subscription models to the “new” v5 model and marking them as backwards compatible — meaning the products could be surfaced and processed by the v4 SDK as well as the SubscriptionsV1 developer API.

In order for a subscription to be backwards compatible, the product must:

  1. Only have 1 base plan
  2. Only have 1 offer
  3. Not use developer-determined eligibility.

Any subscription product configured differently should only be exposed to the user when your backend service has migrated to the SubscriptionsV2 developer API.

Google Billing Library 6

In May 2023, Google released Google Billing Library version 6. The changes in version 6 were much smaller (to consumers) compared to version 5. The biggest change was the addition of a new enum called ReplacementMode which is replacing ProrationMode—these enums define how a subscription upgrade, downgrade, or cross-grade takes effect with regards to timing (immediate vs deferred) and also to charges.

Audible for Android’s Implementation

Audible’s Android team initially integrated with Google Play Billing Library in the spring of 2022. Originally, we onboarded to Library version 4.x, which was the latest at the time, and currently we use Google Billing for all in-app purchases for mandated customers and marketplaces on downloads from the Google Play store.

The Audible Android app is built modularly such that all our Google Billing logic is isolated to a Billing module. The Billing module consists of a BillingClient wrapper, which acts as an interface between Google-specific logic and Audible’s specific business logic. We use a Repository Pattern for fetching and storing information from the Billing SDK (like available in-app products to sell).

All outside consumers interact with the BillingModule through a single interface called the BillingManager. The BillingManager has defined methods needed by UI consumers for displaying prices fetched from the Billing SDK or initiating a purchase through Google Play Billing. The BillingManager in turn calls specific use-cases to handle these app functions.

An infographic showing the high-level architecture of the billing module in the Android Audible app.
High-level architecture of the billing module in the Audible Android app

Motivations for Migrating

Deprecation

Google has a 2-year deprecation cycle on Play Billing versions, meaning our v4 code would need to be migrated eventually, regardless. Furthermore, Google is mandating that by November 1, 2023, all updates to existing apps must use Billing Library version 5 or newer.

Improve the Developer Experience

“Developer-determined” eligibility means that Google will never resolve customer eligibility for a subscription offer (free trial, first month discount, etc.). Instead, it is up to the developer to decide their own eligibility rules. This allows Audible’s Android team to:

  • Improve the module’s testability and code coverage
  • Remove eligibility discrepancies between Audible and Google

In previous Billing Libraries, eligibility has been restricted to either Never had a subscription or Never had this subscription. To test out new subscription offers, we would need a freshly created Google account that had no previous subscription history — otherwise, the account would be deemed ineligible by Google and we’d be unable to make the test transaction. Imagine having to allow-list a new account on the Google Play Console for each test transaction you want to make. That is just not scalable. But with “developer-determined” eligibility, Google will ignore the customer’s subscription history so we can re-use the same Google accounts.

The strict eligibility rules were also limiting in their functionality. Lets say we wanted to offer a free trial to new members and customers who haven’t been members for 1 year yet. This eligibility rule wasn’t supported previously, but now our only limit is our own business logic limitations.

Improve the Customer Experience

The new eligibility rules will also help us improve the customer experience as well. Currently for Audible’s free trial (offered through Google Play Billing), we have an eligibility discrepancy where Audible-specific logic may deem a user eligible for free trial but Google does not. In this flow, a user sees a free trial upsell in the Audible app, but when attempting to launch the billing flow, they receive a message from Google saying they are ineligible for free trial and will be required to pay full price. This is disruptive to the customer experience and may dissuade the user from subscribing.

A screenshot showing the purchasing pop-up.

With the new “developer-determined eligibility,” this flow is not possible as Google will always accept the product and offer with which the app is initiating the purchase.

Migration Challenges

Backwards Compatibility

On a technical level, the library upgrade introduced a new data object to represent an in-app sellable product — ProductDetails, which replaced SkuDetails. The new ProductDetails object contains the new subscription structure. This data model change is reflected in other client API changes or additions, including how the app fetches ProductDetails from the Google Play Billing SDK as well the parameter object to initiate a purchase flow with the BillingClient.

To simplify the migration, we broke it down into two sub-problems.

  1. How do we change our existing code and workflows to the new data model and functions while keeping backwards compatibility with the SubscriptionsV1 developer API?
  2. How do we adopt the new features provided in the new library once our backend has onboarded to the SubscriptionsV2 API?

The ability to migrate the billing client independently from the developer APIs is especially important if backend service teams don’t have the capacity to migrate, and timing a synchronous migration is near impossible.

The core idea in our migration strategy was migrate the client incrementally by adopting the new data model and functions while keeping preexisting functionality, meaning all our subscription products would remain backwards compatible with our backend service for the initial migration release. This strategy allowed us to do several things:

  • Migrate the client app on our own timeline, isolated from backend dependencies
  • Break a large difficult problem into smaller, easier-to-solve problems
  • Ensure any changes wouldn’t interfere with customers on existing subscription products

Outdated Google Play Store Apps

While we were testing out the new library, we noticed an issue where we were unable to make purchases on some devices and emulators. After some further investigation, we discovered that this edge case was because queryProductDetails was failing with a response code of -2BillingResponseCode.FEATURE_NOT_SUPPORTED. This was a surprise — but more importantly, a concern for us. How could a user be able to initialize a BillingClient but be unable to use one of the methods for fetching ProductDetails? Without ProductDetails, we can’t sell any in-app products.

Investigation

By asking Google, we learned that some older Google Play Store apps do not support the new ProductDetails object introduced in Google Billing Library v5. Google had no publicly available data to share and told us we could support both ProductDetails and SkuDetails in the same purchasing flow or collect our own data.

We didn’t want to support both ProductDetails and SkuDetails in the same purchasing flow at once; it would increase the complexity of our migration, and we wouldn’t be able to take advantage of any new benefits of ProductDetails like “developer-determined eligibility.” We would need to ensure all in-app products could be purchased using SkuDetails or ProductDetails for the foreseeable future. Instead we decided to collect our own data to see the impact this would have on our customers.

At BillingClient initialization, we used the BillingClient.isFeatureSupported() method to see if a device would support the new ProductDetails object. We recorded the support data for one month to understand what percentage of our users don’t have support and therefore would be unable to make any in-app purchases after the migration.

Resolution

Although the number of affected customers was low, we still wanted to provide a great customer experience for everyone. We made sure users were informed to update their Google Play Store app and therefore gained support for purchasing capabilities after updating.

The factor which determines if a BillingClient can support ProductDetails is based on the Google Play Store app version on the device. Since the BillingClient is tied to the Google Play Store app, this makes intuitive sense. An old, outdated Google Play Store won’t have support, but a later version will. A user who doesn’t have support for ProductDetails can gain support by updating their Google Play Store app.

To help a customer remediate their purchase experience issues, we show a dialog on a screen used for subscription and credit bundle purchasing — the Membership Details screen (can be found by navigating to Profile → Settings → Details, under Membership). The dialog says:

An error occurred that may limit your ability to make in-app purchases. Please update the Google Play Store app on this device and restart the Audible app.

We show the dialog to customers only when:

  • They don’t have ProductDetails support (via isFeatureSupported())
  • The Membership Details page has a purchase option or upsell through Google Billing.
An example screenshot showing an  error message.

Easy Rollback

We also wanted to retain the ability to easily roll back to the preexisting v4 code path in case there were issues in the v6 implementation we did not catch before release.

NOTE: This was possible because SkuDetails and other v4 models and functions still exist and can be used in v6 but are deprecated.

As mentioned earlier, the BillingManager is accessible to other modules in our app via dependency injection configured by binding an implementation to the BillingManager interface using Dagger. To leverage this pattern and migrate the billing SDK, we created a duplicate BillingManager and code path for the v6 data models and functions and bound the v6 implementation to the BillingManager interface. Thus, if we needed to roll back the new code path, we could do so by injecting the preexisting (and guaranteed working) v4 BillingManager implementation.

An infographic showing the binding implementation of different Google Billing Manager versions.

NOTE: We considered configuring a remote control to act as a dial-up and potentially as an off switch; however, we decided against this approach to reduce complexity. If we introduced a remote dial-up control, we would need to support both code paths simultaneously in the same app version. There could also be edge cases where the remote manager failed to initialize properly.

Takeaways

Our Audible-specific migration strategies allowed us to migrate to the latest Google Play Billing Library isolated from the service-side migration to the latest backend developer APIs. This flexibility allowed us to migrate incrementally to ensure customers on existing subscription products would remain unaffected by the library change. Isolating the client migration from the backend migration also reduced the risks and dependencies to our migration.

I hope our experience in this migration will help guide others form their own migration strategy. Our solutions to the challenges faced were designed around preserving existing functionality and providing the best experience for all customers, including those who may be using outdated software — tenets that are priorities at Audible and in Android development.

--

--

Audible Tech
Audible Tech Blog

Audible is the leading creator and provider of premium audio storytelling.