Skip to content

[in_app_purchase_android] Update to Play Billing Library 9.1.0 - #12781

Open
DL3KB wants to merge 1 commit into
flutter:mainfrom
DL3KB:billing-9.1.0
Open

[in_app_purchase_android] Update to Play Billing Library 9.1.0#12781
DL3KB wants to merge 1 commit into
flutter:mainfrom
DL3KB:billing-9.1.0

Conversation

@DL3KB

@DL3KB DL3KB commented Sep 8, 2026

Copy link
Copy Markdown

Updates com.android.billingclient:billing from 8.0.0 to 9.1.0 in in_app_purchase_android.

Why the minSdk change is required. Play Billing Library 9 declares minSdkVersion 23 in its own AAR manifest (8.0.0 declared 21). With the plugin still on minSdk = 21, the manifest merger fails in any consuming app:

Manifest merger failed : uses-sdk:minSdkVersion 21 cannot be smaller than
version 23 declared in library [com.android.billingclient:billing:9.1.0]

The library module itself still builds at 21, so this only surfaces in the app that consumes the plugin. Raising the plugin's minSdk to 23 makes the constraint explicit. Flutter's own flutter.minSdkVersion is already 24, so there is no practical impact on clients. The same floor is imposed a second time transitively, via play-services-basement 18.9.0.

No removed APIs are used. Diffing the public API of billing-8.0.0.aar against billing-9.1.0.aar shows v9 removes exactly seven classes — SkuDetails, SkuDetailsParams(.Builder), SkuDetailsResponseListener, BillingClient.SkuType, QueryPurchaseHistoryParams(.Builder) — plus BillingFlowParams.Builder.setSkuDetailsList. None appear anywhere under android/src. PurchaseHistoryRecord, which Translator.kt still imports, survives into 9.1.0.

Deprecation. SubscriptionUpdateParams.Builder.setSubscriptionReplacementMode is deprecated as of 8.1.0 but remains functional in 9.x. Because the example builds the plugin with -Xlint:all -Werror, this breaks the build, so it is suppressed with an explanatory comment rather than migrated. Migrating to SubscriptionProductReplacementParams is not a drop-in change: it renumbered the replacement mode constants, which would alter the values carried by the Dart ReplacementMode enum. That belongs in its own breaking change.

Behaviour change reaching clients. Under v9, a Play Store blocked by the system (for example OEM-customized kids mode) reports BILLING_UNAVAILABLE instead of ERROR. The plugin maps response codes 1:1 and branches on neither value, so no plugin code changes; but apps that branch on the code, or match on the stringified code in IAPError.message, are affected. This is called out in the CHANGELOG.

Also corrects the documentation for BillingResponse.billingUnavailable (described the legacy "billing API version not supported" meaning) and BillingResponse.serviceUnavailable (described a network outage, which is what networkError means).

This supersedes #12414, the Dependabot version-only bump, which does not include the required minSdk change and therefore does not build.

Testing

Automated: all existing Dart and native unit tests pass against 9.1.0, and the example app builds.

Manual, against a real Play Console app running this branch with billing 9.1.0:

  • product queries (queryProductDetails) return the expected products, prices and offers
  • restoring past purchases works

Not exercised manually: the subscription replacement path (setSubscriptionReplacementMode), which is the deprecated call suppressed in this PR, and consumable purchase/consumption. Flagging that explicitly since it is the least-covered part of this change — note also that the plugin's unit tests mock BillingClient entirely, so none of them exercise the real library at runtime.

Fixes flutter/flutter#189974

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Test exemption: this is a manual dependency roll, which Tree Hygiene lists as not automatically exempt, so I am requesting one explicitly. The plugin's behaviour is unchanged: response codes are passed through 1:1 (Translator.kt -> pigeon -> pigeon_converters.dart), and no branch in the plugin keys on error or billingUnavailable. The one user-visible change originates in Google's library, not in plugin code, and so cannot be exercised by a plugin test. Happy to add tests if a reviewer sees a seam I have missed.

On the deprecation suppression: if the team would rather take the breaking SubscriptionProductReplacementParams migration now instead of suppressing, I am glad to do that here or in a follow-up — say which you prefer.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2

@google-cla

google-cla Bot commented Sep 8, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the Google Play Billing Library dependency to version 9.1.0, raises the minimum Android SDK version to 23, and updates the documentation for BillingResponse values to reflect behavior changes. Feedback was provided to correct the documentation for BillingResponse.billingUnavailable to more accurately describe the state when billing is unavailable.

Comment on lines +390 to +395
/// A user billing error occurred during processing.
///
/// As of Google Play Billing Library 9, this is also returned when the Play
/// Store app is blocked by the system (for example, in OEM-customized kids
/// mode), a case that previously surfaced as [BillingResponse.error]. Such
/// results carry a `Play Store is blocked` debug message.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The description "A user billing error occurred during processing" is inaccurate for billingUnavailable (which maps to BILLING_UNAVAILABLE). BILLING_UNAVAILABLE indicates that the billing service/API is not supported or is disabled for the current user, device, or product type (e.g., due to parental controls, country restrictions, or being signed out). Consider updating the documentation to more accurately reflect this state.

Suggested change
/// A user billing error occurred during processing.
///
/// As of Google Play Billing Library 9, this is also returned when the Play
/// Store app is blocked by the system (for example, in OEM-customized kids
/// mode), a case that previously surfaced as [BillingResponse.error]. Such
/// results carry a `Play Store is blocked` debug message.
/// Billing is unavailable for the requested product type or user/device state.
///
/// As of Google Play Billing Library 9, this is also returned when the Play
/// Store app is blocked by the system (for example, in OEM-customized kids
/// mode), a case that previously surfaced as [BillingResponse.error]. Such
/// results carry a 'Play Store is blocked' debug message.

Updates com.android.billingclient:billing from 8.0.0 to 9.1.0.

Play Billing Library 9 declares minSdkVersion 23 in its own manifest, so
the plugin's minSdk is raised from 21 to 23. Without this, the manifest
merger fails in any consuming app. Flutter's own minimum is already 24,
so there is no practical impact.

The plugin uses none of the APIs removed in v9 (SkuDetails, SkuDetailsParams,
SkuDetailsResponseListener, BillingClient.SkuType, QueryPurchaseHistoryParams
and BillingFlowParams.Builder.setSkuDetailsList), verified by diffing the
public API of both AARs.

SubscriptionUpdateParams.Builder.setSubscriptionReplacementMode is deprecated
as of 8.1.0 but remains functional in 9.x. It is suppressed rather than
migrated, because SubscriptionProductReplacementParams renumbered the
replacement mode constants and migrating would change the values carried by
the Dart ReplacementMode enum.

Also documents the v9 behaviour change where a Play Store blocked by the
system reports BILLING_UNAVAILABLE instead of ERROR, and corrects the
documentation of BillingResponse.billingUnavailable and
BillingResponse.serviceUnavailable, which described the wrong conditions.
@Piinks
Piinks requested a review from gmackall September 8, 2026 20:47
@Piinks Piinks added the triage-android Should be looked at in Android triage label Sep 8, 2026
@gmackall gmackall added the CICD Run CI/CD label Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD p: in_app_purchase platform-android triage-android Should be looked at in Android triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[in_app_purchase] Update to Google Play Billing Library 9.x

3 participants