Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(google): support Play Billing 9.1 Billing Choice#212

Merged
hyochan merged 14 commits into
mainfrom
feat/google-play-billing-9-1
Jul 10, 2026
Merged

feat(google): support Play Billing 9.1 Billing Choice#212
hyochan merged 14 commits into
mainfrom
feat/google-play-billing-9-1

Conversation

@hyochan

@hyochan hyochan commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

  • Publish OpenIAP Spec 2.1.0 in this PR and target openiap-google 2.3.0 for the CI-promoted stable package.
  • Upgrade the Google implementation to Play Billing 9.1.0 with BILLING_CHOICE, developer-rendered choice metadata/dialog/reporting, originalExternalTransactionId, and showInAppMessagesAndroid.
  • Wire the complete Android surface through React Native/Nitro, Expo, Flutter, Godot, KMP, and MAUI, including hooks, listeners, generated types, examples, and store-specific unsupported behavior.
  • Consolidate the upcoming stable release notes by platform package, IAPKit, and framework library; update Android/API docs and durable parity/release workflow rules.
  • Clarify IAPKit purchases as verification snapshots and update examples to verify, finish, then reverify the same token.

Versioning

  • OpenIAP Spec: 2.1.0 (directly bumped here)
  • openiap-google stable target: 2.3.0 (source remains 2.3.0-rc.1 until CI promotion)
  • openiap-apple stable target: 2.2.5 (source remains 2.2.5-rc.1 until CI promotion)
  • Framework stable targets in release notes: react-native-iap 15.4.0, expo-iap 4.4.0, flutter_inapp_purchase 9.4.0, godot-iap 2.4.0, kmp-iap 2.4.0, OpenIap.Maui 1.2.1

Related

Verification

  • GQL generation and platform sync, including yarn specs for Nitro
  • bun audit:parity, bun audit:docs, and staged diff checks, repeated after a five-minute no-change interval
  • Google Play/Horizon/Amazon compile and unit-test matrix
  • Apple swift build and 104 Swift tests
  • React Native 345 tests plus Android example build across Kotlin/C++ ABIs
  • Expo 303 library tests plus 76 config-plugin tests
  • Flutter analyze plus 281 tests
  • KMP Play/Amazon/Horizon compiles and tests
  • Godot Android/iOS artifact and example checks
  • MAUI shared and Play/Amazon/Horizon builds
  • IAPKit lint, 572 tests, production build, compiled-server smoke probes
  • Docs typecheck, formatting, audit, and production build

Connected-device E2E

  • Google Play / Pixel: exercised Billing Choice availability and showInAppMessagesAndroid; the test account returned program-unavailable and no-action-needed, both handled correctly.
  • Fire OS: reran app launch/catalog fetch and purchase-state reads; the earlier branch matrix covered React Native, Expo, Flutter, and MAUI purchase/fulfill/cancel paths.
  • Vega: reran React Native and Expo launches; the earlier Expo flow completed approved purchase and fulfillment.
  • Apple: physical iPhone on iOS 26.5.2 passes build/install/launch. Purchase UI automation is still blocked because Maestro hangs after detecting the physical device.
  • Meta Horizon: package/framework Horizon builds pass, but connected purchase E2E is blocked because the Quest remains adb unauthorized; the headset must accept the USB debugging prompt.

Preview

The visible changes are API/reference documentation and native SDK examples. Documentation production build and connected example-app launch checks cover those surfaces.

@hyochan hyochan added 🎯 feature New feature 🤖 android Related to android ⬡ gql cross-platform Cross-platform (both Android & iOS) 📖 documentation Improvements or additions to documentation 📘 release Released version 🧪 test Issue or pr related to testing react-native-iap react-native-iap library expo-iap expo-iap library flutter_inapp_purchase flutter_inapp_purchase library godot-iap godot-iap library kmp-iap kmp-iap library maui maui library labels Jul 8, 2026
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Too many files!

This PR contains 198 files, which is 48 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a72a2072-17f2-4c29-ae97-5cb9f75066f5

📥 Commits

Reviewing files that changed from the base of the PR and between b790acf and f1dcbb5.

⛔ Files ignored due to path filters (7)
  • packages/docs/src/generated/version-metadata.json is excluded by !**/generated/**
  • packages/gql/src/generated/Types.cs is excluded by !**/generated/**
  • packages/gql/src/generated/Types.kt is excluded by !**/generated/**
  • packages/gql/src/generated/Types.swift is excluded by !**/generated/**
  • packages/gql/src/generated/types.dart is excluded by !**/generated/**
  • packages/gql/src/generated/types.gd is excluded by !**/generated/**
  • packages/gql/src/generated/types.ts is excluded by !**/generated/**
📒 Files selected for processing (198)
  • .claude/commands/audit-code.md
  • .claude/commands/e2e-tests.md
  • .claude/guides/05-google-package.md
  • .codex/skills/generate-doc/SKILL.md
  • AGENTS.md
  • knowledge/_claude-context/context.md
  • knowledge/external/google-billing-api.md
  • knowledge/external/horizon-api.md
  • knowledge/external/storekit2-api.md
  • knowledge/internal/04-platform-packages.md
  • knowledge/internal/05-docs-patterns.md
  • knowledge/internal/06-git-deployment.md
  • knowledge/internal/sandbox-subscription-billing-issue.md
  • libraries/expo-iap/README.md
  • libraries/expo-iap/android/src/main/java/expo/modules/iap/ExpoIapHelper.kt
  • libraries/expo-iap/android/src/main/java/expo/modules/iap/ExpoIapModule.kt
  • libraries/expo-iap/example/__tests__/subscription-flow.test.tsx
  • libraries/expo-iap/example/app/subscription-flow.tsx
  • libraries/expo-iap/plugin/__tests__/withIAP.test.ts
  • libraries/expo-iap/plugin/src/withIAP.ts
  • libraries/expo-iap/src/__mocks__/expo-modules-core.js
  • libraries/expo-iap/src/__tests__/index.test.ts
  • libraries/expo-iap/src/__tests__/useIAP.test.tsx
  • libraries/expo-iap/src/__tests__/vega-adapter.test.ts
  • libraries/expo-iap/src/index.kepler.ts
  • libraries/expo-iap/src/index.ts
  • libraries/expo-iap/src/modules/__tests__/android.test.ts
  • libraries/expo-iap/src/modules/android.ts
  • libraries/expo-iap/src/modules/ios.ts
  • libraries/expo-iap/src/types.ts
  • libraries/expo-iap/src/useIAP.ts
  • libraries/expo-iap/src/vega-adapter.ts
  • libraries/flutter_inapp_purchase/README.md
  • libraries/flutter_inapp_purchase/android/src/main/kotlin/io/github/hyochan/flutter_inapp_purchase/AndroidInappPurchasePlugin.kt
  • libraries/flutter_inapp_purchase/example/android/app/src/main/AndroidManifest.xml
  • libraries/flutter_inapp_purchase/lib/builders.dart
  • libraries/flutter_inapp_purchase/lib/flutter_inapp_purchase.dart
  • libraries/flutter_inapp_purchase/lib/types.dart
  • libraries/flutter_inapp_purchase/scripts/verify-android-consumer-build.sh
  • libraries/flutter_inapp_purchase/test/builders_unit_test.dart
  • libraries/flutter_inapp_purchase/test/flutter_inapp_purchase_channel_test.dart
  • libraries/godot-iap/CLAUDE.md
  • libraries/godot-iap/Example/export_presets.cfg
  • libraries/godot-iap/Example/project.godot
  • libraries/godot-iap/Example/tests/test_godot_iap.gd
  • libraries/godot-iap/Makefile
  • libraries/godot-iap/README.md
  • libraries/godot-iap/addons/godot-iap/android/GodotIap.release.aar
  • libraries/godot-iap/addons/godot-iap/bin/ios/GodotIap.framework/GodotIap
  • libraries/godot-iap/addons/godot-iap/bin/ios/GodotIap.framework/Info.plist
  • libraries/godot-iap/addons/godot-iap/bin/ios/SwiftGodotRuntime.framework/Info.plist
  • libraries/godot-iap/addons/godot-iap/bin/ios/SwiftGodotRuntime.framework/SwiftGodotRuntime
  • libraries/godot-iap/addons/godot-iap/godot_iap.gd
  • libraries/godot-iap/addons/godot-iap/types.gd
  • libraries/godot-iap/android/build.gradle.kts
  • libraries/godot-iap/android/settings.gradle.kts
  • libraries/godot-iap/android/src/main/java/dev/hyo/godotiap/GodotIap.kt
  • libraries/godot-iap/android/src/main/java/dev/hyo/godotiap/GodotIapHelper.kt
  • libraries/godot-iap/ios-gdextension/Sources/GodotIap/GodotIap.swift
  • libraries/godot-iap/scripts/install-hooks.sh
  • libraries/kmp-iap/README.md
  • libraries/kmp-iap/example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/AlternativeBillingScreen.kt
  • libraries/kmp-iap/example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/AvailablePurchasesScreen.kt
  • libraries/kmp-iap/example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/PurchaseFlowScreen.kt
  • libraries/kmp-iap/example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/SubscriptionFlowScreen.kt
  • libraries/kmp-iap/library/build.gradle.kts
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/AmazonInAppPurchaseAndroid.kt
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/Helper.kt
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseAndroid.kt
  • libraries/kmp-iap/library/src/androidUnitTest/kotlin/io/github/hyochan/kmpiap/AmazonErrorMappingTest.kt
  • libraries/kmp-iap/library/src/androidUnitTest/kotlin/io/github/hyochan/kmpiap/BillingResultMappingTest.kt
  • libraries/kmp-iap/library/src/androidUnitTest/kotlin/io/github/hyochan/kmpiap/DeveloperProvidedBillingReflectionTest.kt
  • libraries/kmp-iap/library/src/androidUnitTest/kotlin/io/github/hyochan/kmpiap/PurchaseTimestampTest.kt
  • libraries/kmp-iap/library/src/androidUnitTest/kotlin/io/github/hyochan/kmpiap/SubscriptionReplacementResolutionTest.kt
  • libraries/kmp-iap/library/src/androidUnitTest/kotlin/io/github/hyochan/kmpiap/UnsupportedGoogleApisTest.kt
  • libraries/kmp-iap/library/src/commonMain/kotlin/io/github/hyochan/kmpiap/dsl/PurchaseDsl.kt
  • libraries/kmp-iap/library/src/commonMain/kotlin/io/github/hyochan/kmpiap/openiap/Types.kt
  • libraries/kmp-iap/library/src/commonTest/kotlin/io/github/hyochan/kmpiap/InAppPurchaseTest.kt
  • libraries/kmp-iap/library/src/iosMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseIOS.kt
  • libraries/kmp-iap/serializeTransaction_enhanced.swift
  • libraries/maui-iap/Directory.Build.props
  • libraries/maui-iap/README.md
  • libraries/maui-iap/android/openiap/src/main/java/dev/hyo/openiap/maui/OpenIapMauiModule.kt
  • libraries/maui-iap/example/OpenIap.Maui.Example/Pages/AlternativeBillingPage.xaml.cs
  • libraries/maui-iap/example/OpenIap.Maui.Example/Pages/PurchaseFlowPage.xaml.cs
  • libraries/maui-iap/example/OpenIap.Maui.Example/Pages/SubscriptionFlowPage.xaml.cs
  • libraries/maui-iap/example/OpenIap.Maui.Example/Utils/ErrorUtils.cs
  • libraries/maui-iap/src/Directory.Build.props
  • libraries/maui-iap/src/OpenIap.Maui.Bindings.Android/OpenIap.Maui.Bindings.Android.csproj
  • libraries/maui-iap/src/OpenIap.Maui/OpenIap.Maui.csproj
  • libraries/maui-iap/src/OpenIap.Maui/Platforms/Android/OpenIapAndroid.Resolvers.cs
  • libraries/maui-iap/src/OpenIap.Maui/Platforms/iOS/OpenIapIOS.cs
  • libraries/maui-iap/src/OpenIap.Maui/Types.cs
  • libraries/react-native-iap/CLAUDE.md
  • libraries/react-native-iap/README.md
  • libraries/react-native-iap/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
  • libraries/react-native-iap/example/__tests__/screens/SubscriptionFlow.test.tsx
  • libraries/react-native-iap/example/android/app/src/main/AndroidManifest.xml
  • libraries/react-native-iap/example/android/build.gradle
  • libraries/react-native-iap/example/screens/AlternativeBilling.tsx
  • libraries/react-native-iap/example/screens/SubscriptionFlow.tsx
  • libraries/react-native-iap/ios/HybridRnIap.swift
  • libraries/react-native-iap/src/__tests__/hooks/useIAP.android.test.ts
  • libraries/react-native-iap/src/__tests__/index.test.ts
  • libraries/react-native-iap/src/__tests__/vega-adapter.test.ts
  • libraries/react-native-iap/src/hooks/useIAP.ts
  • libraries/react-native-iap/src/index.kepler.ts
  • libraries/react-native-iap/src/index.ts
  • libraries/react-native-iap/src/specs/RnIap.nitro.ts
  • libraries/react-native-iap/src/types.ts
  • libraries/react-native-iap/src/vega-adapter.ts
  • openiap-versions.json
  • packages/apple/CONVENTION.md
  • packages/apple/Sources/Models/Types.swift
  • packages/apple/Sources/OpenIapModule+ObjC.swift
  • packages/docs/openiap-versions.json
  • packages/docs/package.json
  • packages/docs/public/llms-full.txt
  • packages/docs/public/llms.txt
  • packages/docs/src/components/CodeBlock.tsx
  • packages/docs/src/lib/images.ts
  • packages/docs/src/lib/searchData.ts
  • packages/docs/src/pages/docs/android-setup.tsx
  • packages/docs/src/pages/docs/apis/android/create-billing-program-reporting-details-android.tsx
  • packages/docs/src/pages/docs/apis/android/enable-billing-program-android.tsx
  • packages/docs/src/pages/docs/apis/android/get-billing-choice-info-android.tsx
  • packages/docs/src/pages/docs/apis/android/is-billing-program-available-android.tsx
  • packages/docs/src/pages/docs/apis/android/launch-external-link-android.tsx
  • packages/docs/src/pages/docs/apis/android/show-billing-program-information-dialog-android.tsx
  • packages/docs/src/pages/docs/apis/android/show-in-app-messages-android.tsx
  • packages/docs/src/pages/docs/apis/deep-link-to-subscriptions.tsx
  • packages/docs/src/pages/docs/apis/index.tsx
  • packages/docs/src/pages/docs/apis/init-connection.tsx
  • packages/docs/src/pages/docs/apis/ios/begin-refund-request-ios.tsx
  • packages/docs/src/pages/docs/apis/ios/clear-transaction-ios.tsx
  • packages/docs/src/pages/docs/apis/ios/present-code-redemption-sheet-ios.tsx
  • packages/docs/src/pages/docs/apis/ios/request-purchase-on-promoted-product-ios.tsx
  • packages/docs/src/pages/docs/apis/ios/sync-ios.tsx
  • packages/docs/src/pages/docs/events.tsx
  • packages/docs/src/pages/docs/events/android/developer-provided-billing-listener-android.tsx
  • packages/docs/src/pages/docs/features/external-purchase.tsx
  • packages/docs/src/pages/docs/foundation/one-pager.tsx
  • packages/docs/src/pages/docs/index.tsx
  • packages/docs/src/pages/docs/kit-backend.tsx
  • packages/docs/src/pages/docs/setup/godot.tsx
  • packages/docs/src/pages/docs/setup/store/horizon.tsx
  • packages/docs/src/pages/docs/types/alternative-billing-types.tsx
  • packages/docs/src/pages/docs/types/billing-programs.tsx
  • packages/docs/src/pages/docs/types/request-purchase-props.tsx
  • packages/docs/src/pages/docs/updates/releases.tsx
  • packages/docs/src/pages/home.tsx
  • packages/docs/src/pages/introduction.tsx
  • packages/google/ALTERNATIVE_BILLING.md
  • packages/google/Example/build.gradle.kts
  • packages/google/Example/src/main/AndroidManifest.xml
  • packages/google/README.md
  • packages/google/gradle.properties
  • packages/google/openiap/build.gradle.kts
  • packages/google/openiap/src/amazon/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/horizon/java/dev/hyo/openiap/store/OpenIapStoreExtensions.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/OpenIapProtocol.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/OpenIapViewModel.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/helpers/CommonHelpers.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/listener/DeveloperProvidedBillingListener.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/listener/OpenIapListener.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/store/OpenIapStore.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingResultConverters.kt
  • packages/google/openiap/src/test/java/dev/hyo/openiap/BillingChoiceAndroidTypesTest.kt
  • packages/google/openiap/src/test/java/dev/hyo/openiap/BillingLibraryClassPathTest.kt
  • packages/google/openiap/src/test/java/dev/hyo/openiap/BillingProgramAndroidTest.kt
  • packages/google/openiap/src/testHorizon/java/dev/hyo/openiap/HorizonAppIdMetadataTest.kt
  • packages/google/openiap/src/testPlay/java/dev/hyo/openiap/QueryPurchasesRaceTest.kt
  • packages/google/openiap/src/testPlay/java/dev/hyo/openiap/utils/BillingResultConvertersTest.kt
  • packages/gql/CONVENTION.md
  • packages/gql/codegen/core/transformer.ts
  • packages/gql/codegen/core/types.ts
  • packages/gql/codegen/plugins/csharp.ts
  • packages/gql/codegen/plugins/dart.ts
  • packages/gql/codegen/plugins/gdscript.ts
  • packages/gql/codegen/plugins/kotlin.ts
  • packages/gql/codegen/plugins/swift.ts
  • packages/gql/package.json
  • packages/gql/src/api-android.graphql
  • packages/gql/src/codegen-defaults.test.ts
  • packages/gql/src/event.graphql
  • packages/gql/src/type-android.graphql
  • packages/gql/src/type-ios.graphql
  • packages/gql/src/type.graphql
  • packages/kit/src/content/faq.md
  • packages/kit/src/pages/auth/organization/project/PurchasesTable.tsx
  • packages/kit/src/pages/auth/organization/project/purchase-detail.tsx
  • packages/kit/src/pages/auth/organization/project/purchases.tsx
  • packages/kit/src/pages/docs/sections/api.tsx
  • scripts/audit-non-godot-parity.mjs
  • scripts/sync-versions.sh

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds Billing Choice, billing-program dialog, and in-app message support across shared schemas, native modules, SDK wrappers, tests, and docs. It also updates reporting-details APIs to accept developerBillingType and refreshes related Billing 9.x references, compatibility notes, and release documentation.

Changes

Billing Choice and in-app message feature implementation

Layer / File(s) Summary
Shared contracts and generated types
packages/gql/src/*, packages/google/openiap/src/*, libraries/*/types.*, packages/apple/Sources/Models/Types.swift
Adds Billing Choice, developer billing type, billing-choice info, billing-program dialog, and in-app message types and resolver signatures across shared schemas and generated type surfaces.
Google Play/Billing native implementations
packages/google/openiap/src/play/*, packages/google/openiap/src/amazon/*, packages/google/openiap/src/horizon/*, libraries/*/android/...
Implements the new Billing Choice and in-app message flows in Play/Amazon/Horizon modules and exposes them through Expo, React Native, Flutter, KMP, Godot, and MAUI bindings.
Tests and parity wiring
packages/google/openiap/src/test*/*, libraries/*/__tests__/*, libraries/*/test*/*, scripts/audit-non-godot-parity.mjs, libraries/*/scripts/*
Adds and updates tests for enum serialization, reflection coverage, wrapper call shapes, and platform-specific unsupported behavior, plus build and parity script updates.
Platform wrappers and examples
libraries/*/android/..., libraries/*/lib/..., libraries/*/src/..., libraries/kmp-iap/example/...
Threads the new APIs through each framework surface and updates the KMP example to exercise Billing Choice as a separate Android path.

Documentation and reference updates

Layer / File(s) Summary
Knowledge base reference documents
knowledge/*, packages/docs/public/llms-full.txt
Refreshes Play Billing 9.x, Horizon compatibility, and StoreKit 2 feature references.
Docs site API and type reference pages
packages/docs/src/pages/docs/*, packages/docs/src/components/CodeBlock.tsx, packages/docs/src/lib/searchData.ts
Adds new Android API pages, updates type/reference pages, and extends docs navigation/search metadata.
Generated docs and package version references
packages/docs/public/llms.txt, packages/google/README.md, packages/google/gradle.properties, packages/docs/public/llms-full.txt
Refreshes generated docs timestamps and version strings shown in package metadata and install snippets.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • hyodotdev/openiap#19: Refactors Horizon/Play flavor wiring in packages/google/openiap, which is directly adjacent to these new Billing Choice and dialog/message API entry points.
  • hyodotdev/openiap#65: Introduces the knowledge-context generation flow that produces knowledge/_claude-context/context.md, the same artifact refreshed in this PR.

Suggested labels: 🎯 feature, 🤖 android

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately captures the main Google Play Billing 9.1 Billing Choice addition.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/google-play-billing-9-1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@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 upgrades the Google Play Billing Library from 8.3.0 to 9.1.0 across the repository, introducing comprehensive support for Billing Choice on Android. It adds new APIs (getBillingChoiceInfoAndroid, showBillingProgramInformationDialogAndroid, and showInAppMessagesAndroid) and updates generated types and documentation across all supported frameworks (React Native, Expo, Flutter, Godot, KMP, and MAUI). The code review identified critical issues, including a type mismatch and serialization bug in the GDScript implementation of InAppMessageParamsAndroid, as well as potential coroutine hangs in both the native Play and KMP Android implementations of showBillingProgramInformationDialog if the synchronous call fails.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread libraries/godot-iap/addons/godot-iap/types.gd
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

1 similar comment
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@coderabbitai coderabbitai 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.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
libraries/kmp-iap/example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/AlternativeBillingScreen.kt (1)

363-372: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Route BillingChoice through a dedicated Billing Choice flow.

Line 369 sends Billing Choice through the generic billing-program flow, which only checks availability, launches an external link, and creates reporting details. The Billing Choice instructions added in this file describe fetching choice metadata, showing the required information dialog, using a billing type, and showing Play in-app messages, so the example’s primary button won’t validate the new APIs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@libraries/kmp-iap/example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/AlternativeBillingScreen.kt`
around lines 363 - 372, Route BillingProgramAndroid.BillingChoice through its
own Billing Choice purchase flow instead of handleAndroidBillingPrograms in
AlternativeBillingScreen.handlePurchase. Update the Android branch to call a
dedicated Billing Choice handler that performs the metadata fetch, required
information dialog, billing type selection, and Play in-app message steps
described in this screen, while leaving BillingProgramAndroid.ExternalOffer,
BillingProgramAndroid.ExternalPayments, and
BillingProgramAndroid.ExternalContentLink on the generic flow.
♻️ Duplicate comments (1)
packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt (1)

1207-1233: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Same responseCode/consistency issue as the Amazon flavor.

showBillingProgramInformationDialog here also returns responseCode = 2 (SERVICE_UNAVAILABLE) instead of FEATURE_NOT_SUPPORTED (-2) for an unsupported-platform condition, and showInAppMessages returns a success-looking NoActionNeeded result rather than signaling the feature is unsupported — while the sibling getBillingChoiceInfo throws FeatureNotSupported. Same root cause as flagged in packages/google/openiap/src/amazon/java/dev/hyo/openiap/OpenIapModule.kt.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt`
around lines 1207 - 1233, Align the unsupported-platform handling in
OpenIapModule’s showBillingProgramInformationDialog and showInAppMessages with
getBillingChoiceInfo and the Amazon variant: these Meta Horizon-only stubs
should signal FEATURE_NOT_SUPPORTED instead of returning a success-like
BillingResultAndroid/InAppMessageResultAndroid. Update the response in
showBillingProgramInformationDialog to the unsupported-feature code and make
showInAppMessages use the same unsupported-path pattern (throwing
OpenIapError.FeatureNotSupported or an equivalent unsupported result), so all
three methods report the same platform limitation consistently.
🧹 Nitpick comments (6)
packages/gql/src/api-android.graphql (1)

69-81: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the new developerBillingType parameter and its BILLING_CHOICE default behavior.

The doc block for createBillingProgramReportingDetailsAndroid (lines 69-75) doesn't mention the new developerBillingType argument at all. Per the native implementation (OpenIapModule.kt), when program == BILLING_CHOICE and developerBillingType is omitted, it silently defaults to IN_APP — non-obvious behavior that should be surfaced in the public API contract for downstream consumers/SDK authors.

📝 Suggested doc addition
   """
   Create the reporting payload Google requires after a Developer-Provided Billing transaction (Play Billing 8.3.0+).
   Replaces the deprecated createExternalOfferReportingDetailsAsync API.
   Returns external transaction token needed for reporting external transactions.
+  developerBillingType is required context for BILLING_CHOICE (Play Billing Library 9.1.0+); if omitted for BILLING_CHOICE, defaults to IN_APP.
   Throws OpenIapError.NotPrepared if billing client not ready.
   See: https://openiap.dev/docs/apis/android/create-billing-program-reporting-details-android
   """
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/gql/src/api-android.graphql` around lines 69 - 81, Update the doc
block for createBillingProgramReportingDetailsAndroid to document the
developerBillingType argument and its default behavior. Mention that this
parameter is optional, and when program is BILLING_CHOICE and
developerBillingType is omitted, the native OpenIapModule.kt behavior defaults
it to IN_APP. Keep the public API contract clear for consumers by reflecting
this behavior in the schema comments near
createBillingProgramReportingDetailsAndroid and BillingProgramAndroid.
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (1)

4601-4612: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

GetBillingChoiceInfoParamsAndroid.fromJson is declared nullable but never returns null.

Unlike the neighboring BillingProgramInformationDialogParamsAndroid.fromJson (which legitimately returns null when externalTransactionToken is missing), this function always constructs a value via defaults. The ? on the return type is misleading and forces unnecessary null-handling on every caller.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt` around lines
4601 - 4612, The companion object method
GetBillingChoiceInfoParamsAndroid.fromJson is marked nullable even though it
always returns a constructed GetBillingChoiceInfoParamsAndroid using defaults.
Update the return type to non-nullable and keep the existing parsing/defaulting
logic intact, mirroring how the method actually behaves; use the fromJson symbol
in GetBillingChoiceInfoParamsAndroid to locate and adjust the signature.
libraries/expo-iap/src/modules/android.ts (1)

396-416: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

createBillingProgramReportingDetailsAndroid loses MutationField type safety.

Every other Android wrapper in this file (getBillingChoiceInfoAndroid, showBillingProgramInformationDialogAndroid, showInAppMessagesAndroid, isBillingProgramAvailableAndroid, launchExternalLinkAndroid) is typed as QueryField<'...'> / MutationField<'...'>, tying its signature to the canonical MutationArgsMap/Mutation contract in types.ts. This function instead uses an untyped union parameter (BillingProgramAndroid | { program; developerBillingType? }) plus a second positional parameter, so it no longer type-checks against MutationCreateBillingProgramReportingDetailsAndroidArgs. If the schema contract changes again, this function won't get a compile-time signal like its siblings do.

If backward compatibility with the old single-string call style is required, consider using proper TypeScript function overloads that still resolve to a MutationField-compatible implementation, so the canonical object-based contract is enforced.

As per coding guidelines, libraries/expo-iap/**/*.{ts,tsx}: "Use type annotations and maintain type safety in TypeScript projects."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libraries/expo-iap/src/modules/android.ts` around lines 396 - 416,
`createBillingProgramReportingDetailsAndroid` should be aligned with the same
`MutationField` type-safety used by the other Android wrappers in this file.
Update its signature to match the canonical
`MutationCreateBillingProgramReportingDetailsAndroidArgs` contract from
`types.ts`, and if you must preserve the old string-style call, use TypeScript
overloads so the implementation still conforms to the mutation field shape. Keep
the implementation in `createBillingProgramReportingDetailsAndroid` and
`ExpoIapModule.createBillingProgramReportingDetailsAndroid` compatible with the
generated args map, rather than relying on an untyped union plus a second
positional parameter.

Source: Coding guidelines

libraries/react-native-iap/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (1)

1819-1945: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Swallowed exceptions lose original stack trace (detekt hint).

The new catch blocks in getBillingChoiceInfoAndroid, showBillingProgramInformationDialogAndroid, and showInAppMessagesAndroid log err and reuse err.message, but don't pass err as the cause of the thrown OpenIapException, so the original stack trace is lost for crash reporting. This matches the pre-existing pattern elsewhere in the class (e.g. checkAlternativeBillingAvailabilityAndroid), so it's a style consistency item rather than a regression introduced by this PR.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@libraries/react-native-iap/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt`
around lines 1819 - 1945, The catch blocks in getBillingChoiceInfoAndroid,
showBillingProgramInformationDialogAndroid, and showInAppMessagesAndroid are
swallowing the original exception cause, so the stack trace is lost. Update the
thrown OpenIapException in each of these methods to include the caught err as
the cause, matching the existing pattern used elsewhere in HybridRnIap. Keep the
current logging and parseOpenIapError/toErrorJson flow, but preserve the
original throwable when rethrowing.

Source: Linters/SAST tools

libraries/react-native-iap/src/__tests__/index.test.ts (1)

2254-2305: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add non-Android rejection tests for parity with getBillingChoiceInfoAndroid.

createBillingProgramReportingDetailsAndroid, showBillingProgramInformationDialogAndroid, and showInAppMessagesAndroid only get Android happy-path tests here, while getBillingChoiceInfoAndroid also has a "should throw on non-Android" test. For consistency and full coverage of the new Android-only surface, consider adding the same negative-path assertion to these three.

As per path instructions, libraries/react-native-iap/**/*.test.{ts,tsx,js,jsx} should "Write tests for all public functions and critical paths."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libraries/react-native-iap/src/__tests__/index.test.ts` around lines 2254 -
2305, Add non-Android rejection coverage for the Android-only APIs to match the
existing `getBillingChoiceInfoAndroid` pattern. In `index.test.ts`, extend the
test blocks for `IAP.createBillingProgramReportingDetailsAndroid`,
`IAP.showBillingProgramInformationDialogAndroid`, and
`IAP.showInAppMessagesAndroid` with assertions that they throw or reject when
`Platform.OS` is not android, using the same style already used for
`getBillingChoiceInfoAndroid`. Keep the focus on the public wrapper methods and
verify no native mock calls are made on non-Android paths.

Source: Path instructions

libraries/maui-iap/android/openiap/src/main/java/dev/hyo/openiap/maui/OpenIapMauiModule.kt (1)

230-244: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor duplication between the two overloads.

createBillingProgramReportingDetailsAndroid and createBillingProgramReportingDetailsAndroidWithType share the same parseProgram + module.createBillingProgramReportingDetails call shape. Consider having the old method delegate to the new one with a null type to avoid drift if the underlying call signature changes again.

♻️ Suggested consolidation
     fun createBillingProgramReportingDetailsAndroid(programJson: String, callback: ResultCallback) = run(callback) {
-        val program = parseProgram(programJson)
-        gson.toJson(module.createBillingProgramReportingDetails(program).toJson())
+        val program = parseProgram(programJson)
+        gson.toJson(module.createBillingProgramReportingDetails(program, null).toJson())
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@libraries/maui-iap/android/openiap/src/main/java/dev/hyo/openiap/maui/OpenIapMauiModule.kt`
around lines 230 - 244, `createBillingProgramReportingDetailsAndroid` and
`createBillingProgramReportingDetailsAndroidWithType` duplicate the same
`parseProgram` plus `module.createBillingProgramReportingDetails` flow, so the
overloads can drift. Update
`OpenIapMauiModule.createBillingProgramReportingDetailsAndroid` to delegate to
`createBillingProgramReportingDetailsAndroidWithType` with a null
developerBillingTypeJson, keeping the parsing and JSON conversion in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libraries/expo-iap/android/src/main/java/expo/modules/iap/ExpoIapModule.kt`:
- Around line 678-706: The categories handling in showInAppMessagesAndroid
currently uses mapNotNull, which silently drops invalid category strings instead
of surfacing a bad input or preserving native default behavior. Update the
categories parsing in ExpoIapModule.kt to either reject unknown values with a
promise.reject/exception or return null when no supplied categories map
successfully, and keep valid categories mapped through mapInAppMessageCategory.
Make the behavior explicit in the AsyncFunction("showInAppMessagesAndroid") flow
so callers don’t get an empty list when they passed only unsupported values.

In `@libraries/godot-iap/addons/godot-iap/types.gd`:
- Around line 4069-4085: `InAppMessageParamsAndroid` is serializing and
deserializing `categories` with raw enum values instead of the JSON string
format expected by Android. Update the generator that produces `types.gd` so
`InAppMessageParamsAndroid.to_dict()` converts each
`InAppMessageCategoryAndroid` entry to its string/json representation, and
`from_dict()` maps each incoming string back through
`InAppMessageCategoryAndroid.fromJson(...)` when populating `categories`.

In `@libraries/godot-iap/android/src/main/java/dev/hyo/godotiap/GodotIap.kt`:
- Around line 861-868: The Billing Choice dialog flow in
GodotIap.showBillingProgramInformationDialog currently falls back to an empty
externalTransactionToken, which hides a required input from callers. Update the
JSON parsing logic to validate externalTransactionToken before constructing
BillingProgramInformationDialogParamsAndroid, and if it is missing or blank,
return a local error/result immediately instead of calling
store.showBillingProgramInformationDialog. Keep the check alongside the existing
billingProgram parsing so the failure is handled in the same GodotIap code path.

In
`@libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseAndroid.kt`:
- Around line 1847-2059: The new reflective entry points in
getBillingChoiceInfoAndroid, showBillingProgramInformationDialogAndroid, and
showInAppMessagesAndroid only check billingClient for null, so a disconnected
stale client can still be used. Add a readiness guard using client.isReady
alongside the existing billingClient check, and fail fast with the same
NotPrepared PurchaseException path before any reflective invocation if the
client is not ready.
- Around line 2063-2072: The reflection-based setup in the In-App message
request builder is constructing InAppMessageParams.Builder with a no-arg
constructor, which will fail at runtime. Update the logic in the
InAppPurchaseAndroid InAppMessageParams setup to obtain the builder via
InAppMessageParams.newBuilder() instead of
Class.forName(...Builder).getConstructor().newInstance(), then keep the existing
category population and build flow unchanged.

In `@libraries/maui-iap/src/OpenIap.Maui/Types.cs`:
- Around line 4081-4092: The MAUI Billing Choice parameter types are stricter
than the underlying schema and other bindings, so callers cannot omit fields
that already have defaults. Update the Android parameter models, especially
BillingProgramInformationDialogParamsAndroid and
GetBillingChoiceInfoParamsAndroid, to either make billingProgram and
playBillingChoiceImageLayout optional or apply their schema defaults before
serialization so the public C# API matches the existing behavior.

In `@packages/docs/src/pages/docs/types/billing-programs.tsx`:
- Around line 412-468: The Android billing docs currently claim billingProgram
defaults to BILLING_CHOICE, but both
BillingProgramInformationDialogParamsAndroid.billingProgram and
GetBillingChoiceInfoParamsAndroid.billingProgram are required and fromJson()
uses BillingProgramAndroid.Unspecified when omitted. Update the summaries in
billing-programs.tsx and the related Android API docs to reflect the required
parameter and the Unspecified fallback, not a BILLING_CHOICE default.

In `@packages/google/openiap/src/amazon/java/dev/hyo/openiap/OpenIapModule.kt`:
- Around line 668-687: The Billing Choice stubs in OpenIapModule should all
return the same unsupported signal so callers can handle Amazon-only behavior
consistently. Update showBillingProgramInformationDialog and showInAppMessages
to use the same permanent not-supported/error path as getBillingChoiceInfo,
instead of returning SERVICE_UNAVAILABLE or NoActionNeeded. Keep the
platform-specific behavior explicit in these methods and align the
returned/raised result with the existing OpenIapError.FeatureNotSupported
pattern.

In `@packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt`:
- Around line 4621-4643: The InAppMessageParamsAndroid.fromJson deserializer
currently relies on InAppMessageCategoryAndroid.fromJson, which can throw on
unknown values and break forward compatibility. Update the categories parsing in
InAppMessageParamsAndroid.Companion.fromJson to safely handle unrecognized
strings by mapping them to UnknownInAppMessageCategoryId instead of calling the
throwing path. Keep the toJson behavior unchanged and make the fallback logic
explicit where the categories list is built.

In `@packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt`:
- Around line 1018-1042: The showInAppMessages flow in OpenIapModule should not
turn a non-OK BillingResult into InAppMessageResultAndroid(NoActionNeeded).
Update the submitResult handling so any immediate failure from the reflective
showInAppMessages invocation is surfaced as an exception or failure result
instead of resuming success; use the existing OpenIapLog and
resumer.resumeWithException/OpenIapError paths alongside showInAppMessages,
BillingResult, and InAppMessageResultAndroid to keep the error visible to
callers.

---

Outside diff comments:
In
`@libraries/kmp-iap/example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/AlternativeBillingScreen.kt`:
- Around line 363-372: Route BillingProgramAndroid.BillingChoice through its own
Billing Choice purchase flow instead of handleAndroidBillingPrograms in
AlternativeBillingScreen.handlePurchase. Update the Android branch to call a
dedicated Billing Choice handler that performs the metadata fetch, required
information dialog, billing type selection, and Play in-app message steps
described in this screen, while leaving BillingProgramAndroid.ExternalOffer,
BillingProgramAndroid.ExternalPayments, and
BillingProgramAndroid.ExternalContentLink on the generic flow.

---

Duplicate comments:
In `@packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt`:
- Around line 1207-1233: Align the unsupported-platform handling in
OpenIapModule’s showBillingProgramInformationDialog and showInAppMessages with
getBillingChoiceInfo and the Amazon variant: these Meta Horizon-only stubs
should signal FEATURE_NOT_SUPPORTED instead of returning a success-like
BillingResultAndroid/InAppMessageResultAndroid. Update the response in
showBillingProgramInformationDialog to the unsupported-feature code and make
showInAppMessages use the same unsupported-path pattern (throwing
OpenIapError.FeatureNotSupported or an equivalent unsupported result), so all
three methods report the same platform limitation consistently.

---

Nitpick comments:
In `@libraries/expo-iap/src/modules/android.ts`:
- Around line 396-416: `createBillingProgramReportingDetailsAndroid` should be
aligned with the same `MutationField` type-safety used by the other Android
wrappers in this file. Update its signature to match the canonical
`MutationCreateBillingProgramReportingDetailsAndroidArgs` contract from
`types.ts`, and if you must preserve the old string-style call, use TypeScript
overloads so the implementation still conforms to the mutation field shape. Keep
the implementation in `createBillingProgramReportingDetailsAndroid` and
`ExpoIapModule.createBillingProgramReportingDetailsAndroid` compatible with the
generated args map, rather than relying on an untyped union plus a second
positional parameter.

In
`@libraries/maui-iap/android/openiap/src/main/java/dev/hyo/openiap/maui/OpenIapMauiModule.kt`:
- Around line 230-244: `createBillingProgramReportingDetailsAndroid` and
`createBillingProgramReportingDetailsAndroidWithType` duplicate the same
`parseProgram` plus `module.createBillingProgramReportingDetails` flow, so the
overloads can drift. Update
`OpenIapMauiModule.createBillingProgramReportingDetailsAndroid` to delegate to
`createBillingProgramReportingDetailsAndroidWithType` with a null
developerBillingTypeJson, keeping the parsing and JSON conversion in one place.

In
`@libraries/react-native-iap/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt`:
- Around line 1819-1945: The catch blocks in getBillingChoiceInfoAndroid,
showBillingProgramInformationDialogAndroid, and showInAppMessagesAndroid are
swallowing the original exception cause, so the stack trace is lost. Update the
thrown OpenIapException in each of these methods to include the caught err as
the cause, matching the existing pattern used elsewhere in HybridRnIap. Keep the
current logging and parseOpenIapError/toErrorJson flow, but preserve the
original throwable when rethrowing.

In `@libraries/react-native-iap/src/__tests__/index.test.ts`:
- Around line 2254-2305: Add non-Android rejection coverage for the Android-only
APIs to match the existing `getBillingChoiceInfoAndroid` pattern. In
`index.test.ts`, extend the test blocks for
`IAP.createBillingProgramReportingDetailsAndroid`,
`IAP.showBillingProgramInformationDialogAndroid`, and
`IAP.showInAppMessagesAndroid` with assertions that they throw or reject when
`Platform.OS` is not android, using the same style already used for
`getBillingChoiceInfoAndroid`. Keep the focus on the public wrapper methods and
verify no native mock calls are made on non-Android paths.

In `@packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt`:
- Around line 4601-4612: The companion object method
GetBillingChoiceInfoParamsAndroid.fromJson is marked nullable even though it
always returns a constructed GetBillingChoiceInfoParamsAndroid using defaults.
Update the return type to non-nullable and keep the existing parsing/defaulting
logic intact, mirroring how the method actually behaves; use the fromJson symbol
in GetBillingChoiceInfoParamsAndroid to locate and adjust the signature.

In `@packages/gql/src/api-android.graphql`:
- Around line 69-81: Update the doc block for
createBillingProgramReportingDetailsAndroid to document the developerBillingType
argument and its default behavior. Mention that this parameter is optional, and
when program is BILLING_CHOICE and developerBillingType is omitted, the native
OpenIapModule.kt behavior defaults it to IN_APP. Keep the public API contract
clear for consumers by reflecting this behavior in the schema comments near
createBillingProgramReportingDetailsAndroid and BillingProgramAndroid.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f12a2a3f-5d9d-4a90-9b62-9929ac6b8272

📥 Commits

Reviewing files that changed from the base of the PR and between f233e76 and f439acc.

⛔ Files ignored due to path filters (7)
  • packages/docs/src/generated/version-metadata.json is excluded by !**/generated/**
  • packages/gql/src/generated/Types.cs is excluded by !**/generated/**
  • packages/gql/src/generated/Types.kt is excluded by !**/generated/**
  • packages/gql/src/generated/Types.swift is excluded by !**/generated/**
  • packages/gql/src/generated/types.dart is excluded by !**/generated/**
  • packages/gql/src/generated/types.gd is excluded by !**/generated/**
  • packages/gql/src/generated/types.ts is excluded by !**/generated/**
📒 Files selected for processing (75)
  • knowledge/_claude-context/context.md
  • knowledge/external/google-billing-api.md
  • knowledge/external/horizon-api.md
  • knowledge/external/storekit2-api.md
  • libraries/expo-iap/android/src/main/java/expo/modules/iap/ExpoIapModule.kt
  • libraries/expo-iap/src/__mocks__/expo-modules-core.js
  • libraries/expo-iap/src/index.kepler.ts
  • libraries/expo-iap/src/modules/__tests__/android.test.ts
  • libraries/expo-iap/src/modules/android.ts
  • libraries/expo-iap/src/types.ts
  • libraries/flutter_inapp_purchase/android/src/main/kotlin/io/github/hyochan/flutter_inapp_purchase/AndroidInappPurchasePlugin.kt
  • libraries/flutter_inapp_purchase/lib/flutter_inapp_purchase.dart
  • libraries/flutter_inapp_purchase/lib/types.dart
  • libraries/flutter_inapp_purchase/test/flutter_inapp_purchase_channel_test.dart
  • libraries/godot-iap/addons/godot-iap/godot_iap.gd
  • libraries/godot-iap/addons/godot-iap/types.gd
  • libraries/godot-iap/android/build.gradle.kts
  • libraries/godot-iap/android/settings.gradle.kts
  • libraries/godot-iap/android/src/main/java/dev/hyo/godotiap/GodotIap.kt
  • libraries/kmp-iap/example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/AlternativeBillingScreen.kt
  • libraries/kmp-iap/library/build.gradle.kts
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/AmazonInAppPurchaseAndroid.kt
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/Helper.kt
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseAndroid.kt
  • libraries/kmp-iap/library/src/commonMain/kotlin/io/github/hyochan/kmpiap/openiap/Types.kt
  • libraries/kmp-iap/library/src/iosMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseIOS.kt
  • libraries/maui-iap/android/openiap/src/main/java/dev/hyo/openiap/maui/OpenIapMauiModule.kt
  • libraries/maui-iap/src/Directory.Build.props
  • libraries/maui-iap/src/OpenIap.Maui/Platforms/Android/OpenIapAndroid.Resolvers.cs
  • libraries/maui-iap/src/OpenIap.Maui/Platforms/iOS/OpenIapIOS.cs
  • libraries/maui-iap/src/OpenIap.Maui/Types.cs
  • libraries/react-native-iap/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
  • libraries/react-native-iap/example/android/build.gradle
  • libraries/react-native-iap/ios/HybridRnIap.swift
  • libraries/react-native-iap/src/__tests__/index.test.ts
  • libraries/react-native-iap/src/index.kepler.ts
  • libraries/react-native-iap/src/index.ts
  • libraries/react-native-iap/src/specs/RnIap.nitro.ts
  • libraries/react-native-iap/src/types.ts
  • libraries/react-native-iap/src/vega-adapter.ts
  • packages/apple/CONVENTION.md
  • packages/apple/Sources/Models/Types.swift
  • packages/docs/public/llms-full.txt
  • packages/docs/public/llms.txt
  • packages/docs/src/components/CodeBlock.tsx
  • packages/docs/src/lib/searchData.ts
  • packages/docs/src/pages/docs/android-setup.tsx
  • packages/docs/src/pages/docs/apis/android/create-billing-program-reporting-details-android.tsx
  • packages/docs/src/pages/docs/apis/android/enable-billing-program-android.tsx
  • packages/docs/src/pages/docs/apis/android/get-billing-choice-info-android.tsx
  • packages/docs/src/pages/docs/apis/android/is-billing-program-available-android.tsx
  • packages/docs/src/pages/docs/apis/android/show-billing-program-information-dialog-android.tsx
  • packages/docs/src/pages/docs/apis/android/show-in-app-messages-android.tsx
  • packages/docs/src/pages/docs/apis/index.tsx
  • packages/docs/src/pages/docs/apis/init-connection.tsx
  • packages/docs/src/pages/docs/index.tsx
  • packages/docs/src/pages/docs/types/alternative-billing-types.tsx
  • packages/docs/src/pages/docs/types/billing-programs.tsx
  • packages/docs/src/pages/docs/updates/releases.tsx
  • packages/google/README.md
  • packages/google/gradle.properties
  • packages/google/openiap/build.gradle.kts
  • packages/google/openiap/src/amazon/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/OpenIapProtocol.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/store/OpenIapStore.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/test/java/dev/hyo/openiap/BillingChoiceAndroidTypesTest.kt
  • packages/google/openiap/src/test/java/dev/hyo/openiap/BillingLibraryClassPathTest.kt
  • packages/google/openiap/src/test/java/dev/hyo/openiap/BillingProgramAndroidTest.kt
  • packages/google/openiap/src/testPlay/java/dev/hyo/openiap/QueryPurchasesRaceTest.kt
  • packages/gql/src/api-android.graphql
  • packages/gql/src/type-android.graphql
  • scripts/audit-non-godot-parity.mjs

Comment thread libraries/godot-iap/addons/godot-iap/types.gd Outdated
Comment thread libraries/maui-iap/src/OpenIap.Maui/Types.cs
Comment thread packages/docs/src/pages/docs/types/billing-programs.tsx
Comment thread packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libraries/flutter_inapp_purchase/scripts/verify-android-consumer-build.sh`:
- Around line 42-68: Add validation in verify-android-consumer-build.sh around
read_google_plugin_version and the perl -0pi edits: after reading the
com.android.library, org.jetbrains.kotlin.plugin.compose, and
com.vanniktech.maven.publish versions, fail fast if any value is empty instead
of writing a blank version into settings.gradle(.kts). Also check each perl
substitution against the settings_file update in both branches so the script
errors out if the plugins block pattern is not found, with a clear message
identifying the affected settings file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b583d5c-a0b2-442b-9198-6ef9c738f59c

📥 Commits

Reviewing files that changed from the base of the PR and between f439acc and 4539d00.

⛔ Files ignored due to path filters (1)
  • packages/gql/src/generated/types.gd is excluded by !**/generated/**
📒 Files selected for processing (5)
  • libraries/flutter_inapp_purchase/scripts/verify-android-consumer-build.sh
  • libraries/godot-iap/addons/godot-iap/types.gd
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseAndroid.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/gql/codegen/plugins/gdscript.ts
✅ Files skipped from review due to trivial changes (1)
  • libraries/godot-iap/addons/godot-iap/types.gd
🚧 Files skipped from review as they are similar to previous changes (2)
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseAndroid.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt

@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 8, 2026
@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 8, 2026
@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 8, 2026
@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 8, 2026

@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 introduces support for Google Play Billing Library 9.1.0, specifically adding the Billing Choice API and associated features such as in-app messaging and reporting details. The changes span across the core Android library, documentation, and various framework wrappers (React Native, Expo, Flutter, KMP, Godot, and MAUI). A code review comment regarding nullable enum parsing in the Kotlin generator was identified as a valid improvement opportunity and should be addressed.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/gql/codegen/plugins/kotlin.ts

@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 upgrades the Google Play Billing Library integration from version 8.3.0 to 9.1.0 across all supported frameworks (React Native, Expo, Flutter, Godot, KMP, and MAUI). It introduces comprehensive support for the Billing Choice API, including new endpoints and types for fetching choice display assets, showing information dialogs, and handling in-app messages. Codegen plugins have also been updated to support default values from the GraphQL schema. The reviewer feedback suggests adding default empty object initializers to the getBillingChoiceInfoAndroid parameters in the React Native and Expo wrappers to prevent potential runtime TypeErrors when called without arguments.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread libraries/react-native-iap/src/index.ts
Comment thread libraries/expo-iap/src/modules/android.ts

@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 upgrades the Google Play Billing Library dependency from 8.3.0 to 9.1.0 and implements support for Google Play Billing Choice across all framework libraries (React Native, Expo, Flutter, KMP, Godot, and MAUI). Key additions include new Android-specific APIs: getBillingChoiceInfoAndroid for developer-rendered choice screens, showBillingProgramInformationDialogAndroid for Google-rendered choice flows, and showInAppMessagesAndroid for displaying Play Billing in-app messages. Additionally, createBillingProgramReportingDetailsAndroid now accepts an optional developerBillingType parameter. Documentation, generated types, and test suites have been updated accordingly to maintain platform parity. There are no review comments, and I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt (1)

810-831: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Make Horizon’s unsupported Billing Choice paths consistent
showBillingProgramInformationDialogAndroid and showInAppMessagesAndroid return placeholder results when Activity is missing, but the Horizon overrides still throw FeatureNotSupported. Use one failure shape for both branches so callers don’t have to handle result-vs-exception behavior differently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt`
around lines 810 - 831, The Horizon overrides for
showBillingProgramInformationDialogAndroid and showInAppMessagesAndroid
currently mix placeholder result returns with FeatureNotSupported exceptions,
which creates inconsistent failure handling. Update the OpenIapModule.kt
implementations so both unsupported paths use the same failure shape as the rest
of the API, either by consistently returning the corresponding result object or
consistently throwing FeatureNotSupported from the named lambdas, and make the
behavior match across both functions.
packages/gql/codegen/plugins/dart.ts (1)

838-849: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

List cast crashes before default fallback can apply for non-nullable lists with schema defaults.

listCast only appends ? when type.nullable is true. When a field is a non-null list ([X!]!) that also has a GraphQL default value (e.g. categories: [Category!]! = [FOO], a real and common GraphQL pattern), defaultExpression is set but type.nullable is false, so listCast becomes (${sourceExpr} as List<dynamic>) — a non-nullable cast. In Dart, casting null to a non-nullable type throws a TypeError immediately, so the ${listCast} == null ? ${defaultExpression} : ... check never gets a chance to apply the fallback — it crashes instead of using the default.

🐛 Proposed fix
     if (type.kind === 'list') {
-      const listCast = `(${sourceExpr} as List<dynamic>${type.nullable ? '?' : ''})`;
+      const listCast = `(${sourceExpr} as List<dynamic>${type.nullable || defaultExpression ? '?' : ''})`;
       const elementExpr = this.buildFromJsonExpression(type.elementType!, 'e');
       const mapCall = (target: string) => `${target}.map((e) => ${elementExpr}).toList()`;
       if (defaultExpression) {
-        return `${listCast} == null ? ${defaultExpression} : ${mapCall(`${listCast}${type.nullable ? '!' : ''}`)}`;
+        return `${listCast} == null ? ${defaultExpression} : ${mapCall(`${listCast}!`)}`;
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/gql/codegen/plugins/dart.ts` around lines 838 - 849, The
buildFromJsonExpression list branch currently applies a non-nullable cast before
checking defaultExpression, so non-null list fields with schema defaults can
throw on null before the fallback runs. Update the list handling in
buildFromJsonExpression so the null check happens on the raw sourceExpr (or use
a nullable cast whenever defaultExpression is present), then only cast/map after
the default fallback has been selected. Keep the behavior aligned for both
nullable and non-nullable list types, especially when defaultExpression is set.
♻️ Duplicate comments (1)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (1)

4441-4467: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Past-review pattern not applied to the new Billing Choice enum parsers.

GetBillingChoiceInfoParamsAndroid.fromJson (Lines 4602-4609) and BillingProgramInformationDialogParamsAndroid.fromJson (Line 4453) parse billingProgram/playBillingChoiceImageLayout without runCatching, unlike the pervasive runCatching { EnumType.fromJson(it) }.getOrNull() ?: Unknown pattern used elsewhere in this file (and unlike the fix already applied to InAppMessageParamsAndroid.categories). If these enums throw on unrecognized/future raw values, these deserializers will crash instead of degrading gracefully.

Please confirm whether BillingProgramAndroid/BillingChoiceImageLayoutAndroid have an Unknown-style fallback member; if so, wrap their fromJson calls in runCatching the same way as the other enums in this file.

Also applies to: 4587-4616

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt` around lines
4441 - 4467, The Billing Choice enum parsing in
BillingProgramInformationDialogParamsAndroid.fromJson and
GetBillingChoiceInfoParamsAndroid.fromJson is still calling fromJson directly,
unlike the rest of this file’s safe enum parsing pattern. Update the parsing in
these methods to use runCatching around BillingProgramAndroid.fromJson and
BillingChoiceImageLayoutAndroid.fromJson, then fall back to the corresponding
Unknown-style member if present; if no fallback exists, add one consistently.
Keep the fix aligned with the existing enum deserializers in Types.kt and with
the already-correct InAppMessageParamsAndroid.categories handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/gql/codegen/plugins/csharp.ts`:
- Around line 411-417: In csharp.ts, fix the non-nullable property emission in
the branch that uses buildDefaultValueExpression so that if the default cannot
be converted, the property falls back to being marked required instead of being
emitted without required or an initializer. Also update
buildDefaultValueForType’s string handling to escape C# string literal
characters such as " and \ before interpolating the default value, so generated
properties in emit stay valid.

In `@packages/gql/codegen/plugins/kotlin.ts`:
- Around line 895-901: The scalar default formatting in the Kotlin codegen path
is treating all numeric defaults the same, which causes whole-number
Float/Double defaults to emit invalid Kotlin literals. Update the default-value
formatting logic in the scalar-handling branch of the Kotlin plugin so it checks
the target GraphQL scalar type before serializing numbers, and when the field
maps to Float/Double, emit a Kotlin floating-point literal instead of using
String(defaultValue). Keep the existing string/boolean handling intact, and
adjust the helper that formats defaults so it can distinguish the Float scalar
case.

---

Outside diff comments:
In `@packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt`:
- Around line 810-831: The Horizon overrides for
showBillingProgramInformationDialogAndroid and showInAppMessagesAndroid
currently mix placeholder result returns with FeatureNotSupported exceptions,
which creates inconsistent failure handling. Update the OpenIapModule.kt
implementations so both unsupported paths use the same failure shape as the rest
of the API, either by consistently returning the corresponding result object or
consistently throwing FeatureNotSupported from the named lambdas, and make the
behavior match across both functions.

In `@packages/gql/codegen/plugins/dart.ts`:
- Around line 838-849: The buildFromJsonExpression list branch currently applies
a non-nullable cast before checking defaultExpression, so non-null list fields
with schema defaults can throw on null before the fallback runs. Update the list
handling in buildFromJsonExpression so the null check happens on the raw
sourceExpr (or use a nullable cast whenever defaultExpression is present), then
only cast/map after the default fallback has been selected. Keep the behavior
aligned for both nullable and non-nullable list types, especially when
defaultExpression is set.

---

Duplicate comments:
In `@packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt`:
- Around line 4441-4467: The Billing Choice enum parsing in
BillingProgramInformationDialogParamsAndroid.fromJson and
GetBillingChoiceInfoParamsAndroid.fromJson is still calling fromJson directly,
unlike the rest of this file’s safe enum parsing pattern. Update the parsing in
these methods to use runCatching around BillingProgramAndroid.fromJson and
BillingChoiceImageLayoutAndroid.fromJson, then fall back to the corresponding
Unknown-style member if present; if no fallback exists, add one consistently.
Keep the fix aligned with the existing enum deserializers in Types.kt and with
the already-correct InAppMessageParamsAndroid.categories handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4bba7c7e-56d7-463b-870b-b719b9ac702a

📥 Commits

Reviewing files that changed from the base of the PR and between 4539d00 and 1f9f2e5.

⛔ Files ignored due to path filters (5)
  • packages/gql/src/generated/Types.cs is excluded by !**/generated/**
  • packages/gql/src/generated/Types.kt is excluded by !**/generated/**
  • packages/gql/src/generated/Types.swift is excluded by !**/generated/**
  • packages/gql/src/generated/types.dart is excluded by !**/generated/**
  • packages/gql/src/generated/types.ts is excluded by !**/generated/**
📒 Files selected for processing (28)
  • libraries/expo-iap/android/src/main/java/expo/modules/iap/ExpoIapModule.kt
  • libraries/expo-iap/src/modules/__tests__/android.test.ts
  • libraries/expo-iap/src/modules/android.ts
  • libraries/expo-iap/src/types.ts
  • libraries/flutter_inapp_purchase/lib/types.dart
  • libraries/flutter_inapp_purchase/scripts/verify-android-consumer-build.sh
  • libraries/godot-iap/android/src/main/java/dev/hyo/godotiap/GodotIap.kt
  • libraries/kmp-iap/example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/AlternativeBillingScreen.kt
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseAndroid.kt
  • libraries/kmp-iap/library/src/commonMain/kotlin/io/github/hyochan/kmpiap/openiap/Types.kt
  • libraries/maui-iap/android/openiap/src/main/java/dev/hyo/openiap/maui/OpenIapMauiModule.kt
  • libraries/maui-iap/src/OpenIap.Maui/Types.cs
  • libraries/react-native-iap/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
  • libraries/react-native-iap/src/__tests__/index.test.ts
  • libraries/react-native-iap/src/index.ts
  • libraries/react-native-iap/src/types.ts
  • packages/apple/Sources/Models/Types.swift
  • packages/google/openiap/src/amazon/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/horizon/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/gql/codegen/core/transformer.ts
  • packages/gql/codegen/core/types.ts
  • packages/gql/codegen/plugins/csharp.ts
  • packages/gql/codegen/plugins/dart.ts
  • packages/gql/codegen/plugins/kotlin.ts
  • packages/gql/codegen/plugins/swift.ts
  • packages/gql/src/api-android.graphql
✅ Files skipped from review due to trivial changes (6)
  • libraries/flutter_inapp_purchase/lib/types.dart
  • libraries/react-native-iap/src/types.ts
  • libraries/expo-iap/src/types.ts
  • packages/apple/Sources/Models/Types.swift
  • libraries/kmp-iap/library/src/commonMain/kotlin/io/github/hyochan/kmpiap/openiap/Types.kt
  • libraries/maui-iap/src/OpenIap.Maui/Types.cs
🚧 Files skipped from review as they are similar to previous changes (13)
  • libraries/flutter_inapp_purchase/scripts/verify-android-consumer-build.sh
  • libraries/expo-iap/src/modules/tests/android.test.ts
  • libraries/maui-iap/android/openiap/src/main/java/dev/hyo/openiap/maui/OpenIapMauiModule.kt
  • packages/gql/src/api-android.graphql
  • packages/google/openiap/src/amazon/java/dev/hyo/openiap/OpenIapModule.kt
  • libraries/react-native-iap/src/index.ts
  • libraries/expo-iap/src/modules/android.ts
  • libraries/expo-iap/android/src/main/java/expo/modules/iap/ExpoIapModule.kt
  • libraries/godot-iap/android/src/main/java/dev/hyo/godotiap/GodotIap.kt
  • libraries/react-native-iap/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
  • libraries/react-native-iap/src/tests/index.test.ts
  • libraries/kmp-iap/library/src/androidMain/kotlin/io/github/hyochan/kmpiap/InAppPurchaseAndroid.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt

Comment thread packages/gql/codegen/plugins/csharp.ts Outdated
Comment thread packages/gql/codegen/plugins/kotlin.ts

@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 upgrades the Google Play Billing Library from version 8.3.0 to 9.1.0 across multiple frameworks (React Native, Expo, Flutter, KMP, Godot, and MAUI) and introduces support for Billing Choice APIs. The code review feedback suggests simplifying a ternary operator in the React Native implementation of createBillingProgramReportingDetailsAndroid and removing a dead synchronous return value check on showBillingProgramInformationDialog in the Android KMP implementation.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread libraries/react-native-iap/src/index.ts Outdated
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

1 similar comment
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@hyochan hyochan force-pushed the feat/google-play-billing-9-1 branch from dd1afdd to 11fb5c8 Compare July 9, 2026 09:45
Bump the OpenIAP spec to 2.1.0, align framework hooks and store-specific unsupported behavior, consolidate stable release notes, and preserve verification lifecycle guidance.

Closes #221
@hyochan hyochan force-pushed the feat/google-play-billing-9-1 branch from 11fb5c8 to 94bd0a7 Compare July 10, 2026 22:33

@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 upgrades the Google Play Billing Library integration to version 9.1.0 and the Meta Horizon Billing Compatibility SDK to version 2.0.0 across the monorepo wrapper libraries, introducing Billing Choice APIs, developer billing reporting, and in-app billing messages. The code review identified two critical issues: a backward-compatibility bug in the Kotlin Multiplatform reflective listener proxy for Play Billing 8.3.0 that could prevent token emission, and a serialization failure in the GDScript wrapper where custom RefCounted objects are passed directly to JSON.stringify without being converted to dictionaries first.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread libraries/godot-iap/addons/godot-iap/godot_iap.gd
Keep KMP developer billing payload extraction compatible with Billing 8.3 details and serialize nested Godot purchase parameters before crossing the native bridge.

@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 upgrades the Google Play Billing Library integration from version 8.x to 9.1.0 across the monorepo, introducing support for Billing Choice APIs, developer-provided billing options, and transactional in-app messages. It also updates the Meta Horizon Billing Compatibility SDK to version 2.0.0, transitioning to the canonical Horizon App ID manifest key, and adds experimental support for Amazon Fire OS and Vega OS. Corresponding updates, types, and tests have been added across all wrapper libraries (React Native, Expo, Flutter, Godot, KMP, and MAUI). Feedback was provided regarding a style guide violation where the shared spec version was bumped to 2.1.0 in openiap-versions.json without the corresponding update to packages/gql/package.json.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread openiap-versions.json

@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 OpenIAP project to support Google Play Billing 9.1.0, including the new Billing Choice APIs, in-app messaging, and developer-provided billing enhancements. It also updates the Amazon Fire OS and Vega OS integrations, improves the IAPKit verification logic with timeouts, and updates documentation and SDK parity checklists. Several review comments identified critical issues regarding the use of withTimeout in retry loops, reflection-based compatibility fallbacks for Billing Library versions, and missing await keywords in Godot tests, which are addressed by the review indices marked for removal.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 10, 2026
@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 10, 2026
@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 10, 2026
@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 10, 2026
@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 10, 2026
@hyodotdev hyodotdev deleted a comment from coderabbitai Bot Jul 10, 2026
@hyochan hyochan merged commit 0c391ee into main Jul 10, 2026
22 checks passed
@hyochan hyochan deleted the feat/google-play-billing-9-1 branch July 10, 2026 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🤖 android Related to android cross-platform Cross-platform (both Android & iOS) 📖 documentation Improvements or additions to documentation expo-iap expo-iap library 🎯 feature New feature flutter_inapp_purchase flutter_inapp_purchase library godot-iap godot-iap library ⬡ gql kmp-iap kmp-iap library maui maui library react-native-iap react-native-iap library 📘 release Released version 🧪 test Issue or pr related to testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FR] Support BillingClient.showInAppMessages() (Android in-app messaging)

1 participant