Skip to content

feat(google): upgrade to Google Play Billing Library 8.1.0#50

Merged
hyochan merged 4 commits into
mainfrom
feat/android-billing-8.1.0
Dec 9, 2025
Merged

feat(google): upgrade to Google Play Billing Library 8.1.0#50
hyochan merged 4 commits into
mainfrom
feat/android-billing-8.1.0

Conversation

@hyochan
Copy link
Copy Markdown
Member

@hyochan hyochan commented Dec 9, 2025

  • Upgrade Billing Library from 8.0.0 to 8.1.0
  • Increase minSdk from 21 to 23 (Android 6.0)
  • Upgrade Kotlin from 2.0.21 to 2.2.0

New features:

  • isSuspendedAndroid: Detect suspended subscriptions due to payment failures
  • PreorderDetailsAndroid: Support for pre-order products with presale end time and release time

GQL schema updates:

  • Add PreorderDetailsAndroid type with preorderPresaleEndTimeMillis and preorderReleaseTimeMillis
  • Add isSuspendedAndroid field to PurchaseAndroid

Documentation:

  • Update types page with new Android fields
  • Add release notes for openiap-google v1.3.11 / openiap-gql v1.3.1
  • Add Google Play Billing 8.1.0 section to recent updates
  • Include links to official release notes

Summary by CodeRabbit

  • New Features

    • Added Google Play Billing 8.1.0 support, exposing pre-order timing details for one‑time purchases and surfacing suspended subscription state.
  • Chores

    • Raised Android minimum SDK to 23 and updated Kotlin/tooling versions (Compose compiler aligned).
  • Documentation

    • Added docs, release notes, and migration guidance for Billing 8.1.0 and the new Android-specific fields.

✏️ Tip: You can customize this high-level summary in your review settings.

- Upgrade Billing Library from 8.0.0 to 8.1.0
- Increase minSdk from 21 to 23 (Android 6.0)
- Upgrade Kotlin from 2.0.21 to 2.2.0

New features:
- isSuspendedAndroid: Detect suspended subscriptions due to payment failures
- PreorderDetailsAndroid: Support for pre-order products with presale end time and release time

GQL schema updates:
- Add PreorderDetailsAndroid type with preorderPresaleEndTimeMillis and preorderReleaseTimeMillis
- Add isSuspendedAndroid field to PurchaseAndroid

Documentation:
- Update types page with new Android fields
- Add release notes for openiap-google v1.3.11 / openiap-gql v1.3.1
- Add Google Play Billing 8.1.0 section to recent updates
- Include links to official release notes
@hyochan hyochan added 🎯 feature New feature 🤖 android Related to android labels Dec 9, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 9, 2025

Walkthrough

Adds Android preorder and suspended-subscription fields across models, conversion logic, GraphQL schema, docs, and build configs to support Google Play Billing Library 8.1.0.

Changes

Cohort / File(s) Summary
Android Kotlin types
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
Added PreorderDetailsAndroid data class; added preorderDetailsAndroid to ProductAndroidOneTimePurchaseOfferDetail; added isSuspendedAndroid to PurchaseAndroid; updated JSON (de)serialization.
Android conversion & runtime
packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingConverters.kt, packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
Extracted preorder details from one-time purchase offers and mapped to PreorderDetailsAndroid; added reflection-based detection of suspended subscriptions and threaded isSuspendedAndroid into PurchaseAndroid; updated user-facing strings and added suppression/comments for deprecated Billing API.
iOS/Apple models
packages/apple/Sources/Models/Types.swift
Added PreorderDetailsAndroid struct; optional preorderDetailsAndroid on one-time offer detail; optional isSuspendedAndroid on purchase model; updated (de)serialization members.
GraphQL schema
packages/gql/src/type-android.graphql
Added PreorderDetailsAndroid type and fields; added preorderDetailsAndroid to ProductAndroidOneTimePurchaseOfferDetail; added isSuspendedAndroid to PurchaseAndroid.
Build & dependency updates
packages/google/build.gradle.kts, packages/google/openiap/build.gradle.kts, packages/google/gradle.properties
Bumped Kotlin plugin and Compose compiler versions (Kotlin → 2.2.0); raised minSdk 21→23; upgraded Google Play Billing deps 8.0.0→8.1.0.
Documentation & release notes
packages/docs/src/pages/docs/types.tsx, packages/docs/src/pages/docs/updates/notes.tsx
Documented preorderDetailsAndroid and isSuspendedAndroid, updated Android one-time purchase display, added Billing 8.1.0 notes, migration guidance, and version compatibility updates.
Package manifest
package.json
Manifest updated; no code-level API changes reported.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing careful review:
    • packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingConverters.kt — reflection logic for detecting suspension and preorder extraction.
    • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt and packages/apple/Sources/Models/Types.swift — new types and JSON (de)serialization correctness and nullability alignment.
    • packages/gql/src/type-android.graphql — schema nullability/types vs runtime fields.
    • Build files (build.gradle.kts, gradle.properties) and minSdk bump — cross-module compatibility.

Possibly related PRs

Poem

Hop hop, I sniff the Play Store breeze,
Preorders tick and suspensions freeze,
Fields hop into models, docs sing too,
Kotlin jumps forward — builds say woohoo,
A rabbit claps tiny paws, code anew 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: upgrading to Google Play Billing Library 8.1.0, which is the primary objective and focus of this pull request.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/android-billing-8.1.0

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 382bb90 and ff1f90d.

📒 Files selected for processing (1)
  • packages/docs/src/pages/docs/updates/notes.tsx (7 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: iOS-specific functions must end with IOS suffix (e.g., clearTransactionIOS, getAppTransactionIOS)
Android-specific functions must end with Android suffix (e.g., acknowledgePurchaseAndroid, consumePurchaseAndroid)
Use action prefixes for function naming: get for retrieval, request for async operations, clear for removal, is/has for boolean checks, show/present for UI display, begin/finish/end for process control

Prefer interface for defining object shapes in TypeScript

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/docs/**/*.{ts,tsx}: Use kebab-case for search modal IDs (e.g., id: 'request-products')
Modal state should be defined once at the app root level using Preact Signals (signal from '@preact/signals-react'), not instantiated multiple times
ALL components must fit within parent boundaries and never overflow outside parent containers; use overflow-hidden, break-words, and whitespace-nowrap as needed
Delete unused components, functions, and imports immediately; do not keep commented-out code or unused variables
ANY function that returns a Promise must be wrapped with void operator when used where a void return is expected (e.g., event handlers)

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

packages/docs/**/*: Before committing, run npx prettier --write, npm run lint, bun run tsc or npm run typecheck, and npm run build to verify formatting, linting, types, and build success
Use conventional commit format with lowercase type prefix and lowercase description (e.g., feat: add user authentication)

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{ts,tsx,js,jsx}: Use camelCase for variable and function names
Use PascalCase for class and component names
Always use async/await for handling promises instead of .then() chains
Add JSDoc comments for public functions and exported APIs
Use const by default, let if reassignment is needed, avoid var

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/docs/**/*.{md,mdx} : Use kebab-case for URL anchors (e.g., `#fetch-products`, `#get-app-transaction-ios`)

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to **/*.{ts,tsx} : Android-specific functions must end with `Android` suffix (e.g., `acknowledgePurchaseAndroid`, `consumePurchaseAndroid`)

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
🧬 Code graph analysis (1)
packages/docs/src/pages/docs/updates/notes.tsx (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (2)
  • code (1334-1356)
  • code (1886-1905)
packages/gql/src/generated/Types.kt (2)
  • code (1401-1423)
  • code (1953-1972)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test Android
🔇 Additional comments (8)
packages/docs/src/pages/docs/updates/notes.tsx (8)

85-100: LGTM!

The Kotlin code example clearly demonstrates the new APIs and follows the Android suffix naming convention (isSuspendedAndroid, preorderDetailsAndroid). The .toLong() conversion is appropriate since millisecond timestamps are typically represented as Strings in GraphQL schemas to avoid precision issues.


128-129: LGTM!

Minor formatting improvement for JSX readability.


193-195: LGTM!

Strikethrough styling appropriately indicates the deprecated API, consistent with other deprecated items in the document.


270-272: LGTM!

Improved link wrapping for better code readability.


517-528: LGTM!

Version compatibility table accurately reflects the Billing Library 8.1.0 upgrade requirements (minSdk 23, Kotlin 2.2.0) and properly positions v8.x as the current recommended version.


555-588: LGTM!

The release date has been corrected to November 6, 2025, addressing the previous review concern. The section comprehensively covers the Billing Library 8.1.0 features including suspended subscriptions, pre-order support, SDK requirements, and the deprecated setSubscriptionReplacementMode() API.


534-534: LGTM!

Accurate description update for v6.x row.


103-106: The #purchase-platform anchor exists and the internal link is correct.

The anchor at packages/docs/src/pages/docs/types.tsx:863 confirms that the link to #purchase-platform is valid. Both referenced anchors (#purchase-platform at line 863 and #product-platform at line 293) are correctly defined in the types documentation.


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
packages/google/openiap/build.gradle.kts (1)

20-24: Billing 8.1.0 + minSdk 23 wiring looks correct; POM description is slightly vague

The Gradle updates for minSdk = 23 and billing-ktx:8.1.0 (play compile/runtime + tests) are consistent and should be fine. The POM description still says “Google Play Billing v8”, which is technically correct but not version-specific; if you want ultra-clear release metadata, consider updating it to “v8.1.0” or “v8.x” so it doesn’t drift from the dependency in future bumps.

Also applies to: 89-91, 115-116

packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt (2)

635-641: Acceptable use of deprecated setSubscriptionReplacementMode, but plan a future migration

The added comment + @Suppress("DEPRECATION") around setSubscriptionReplacementMode(replacementMode) make it clear you’re intentionally relying on the legacy API for single‑product upgrades under Billing 8.1.0. That’s fine for now, but it would be good to track a follow‑up to migrate to SubscriptionProductReplacementParams so you’re aligned with the current API surface and ready for any future removals.


436-437: Hard‑coded “Billing 8.1.0” strings may drift from the actual dependency

Both the alternative‑billing error message and the initialization log embed "Billing 8.1.0" as a literal. This is helpful today but easy to forget when bumping the Gradle dependency again; if they get out of sync, the logs will be misleading when debugging billing issues. Consider either making the text version‑agnostic (e.g. “Billing 8.x+”) or pulling the version from a single constant/BuildConfig so it stays in sync automatically.

Also applies to: 1081-1092

packages/gql/src/type-android.graphql (1)

17-32: Schema additions for preorderDetailsAndroid and isSuspendedAndroid look correct and backward‑compatible

PreorderDetailsAndroid and its use on ProductAndroidOneTimePurchaseOfferDetail, plus the isSuspendedAndroid flag on PurchaseAndroid, are all additive, nullable at the entry point, and match the generated Kotlin/Swift types (String millis + Boolean). This is a safe extension of the API for Billing 8.1.0 features. Just ensure you’ve re-run bun run generate and the platform bindings (Kotlin/Swift/TS/Dart) are regenerated from this schema so everything stays in lockstep. Based on learnings, this should also be wired via the gql version in openiap-versions.json.

Also applies to: 38-42, 118-125

packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingConverters.kt (1)

96-102: Missing preorderDetailsAndroid in subscription product conversion.

The toSubscriptionProduct() method at lines 96-102 creates a ProductAndroidOneTimePurchaseOfferDetail but doesn't include the preorderDetailsAndroid field, unlike the toInAppProduct() method. While pre-orders are typically for one-time purchases, this inconsistency could cause issues if the field is ever needed for subscriptions.

For consistency with toInAppProduct(), consider extracting pre-order details here as well:

 oneTimePurchaseOfferDetailsAndroid = oneTimePurchaseOfferDetails?.let {
+    val preorderDetails = it.preorderDetails?.let { preorder ->
+        PreorderDetailsAndroid(
+            preorderPresaleEndTimeMillis = preorder.preorderPresaleEndTimeMillis.toString(),
+            preorderReleaseTimeMillis = preorder.preorderReleaseTimeMillis.toString()
+        )
+    }
     ProductAndroidOneTimePurchaseOfferDetail(
         formattedPrice = it.formattedPrice,
         priceAmountMicros = it.priceAmountMicros.toString(),
-        priceCurrencyCode = it.priceCurrencyCode
+        priceCurrencyCode = it.priceCurrencyCode,
+        preorderDetailsAndroid = preorderDetails
     )
 },
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8464392 and 1ebe1e5.

⛔ Files ignored due to path filters (4)
  • 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 (9)
  • packages/apple/Sources/Models/Types.swift (3 hunks)
  • packages/docs/src/pages/docs/types.tsx (2 hunks)
  • packages/docs/src/pages/docs/updates/notes.tsx (3 hunks)
  • packages/google/build.gradle.kts (1 hunks)
  • packages/google/openiap/build.gradle.kts (3 hunks)
  • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (7 hunks)
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt (3 hunks)
  • packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingConverters.kt (5 hunks)
  • packages/gql/src/type-android.graphql (2 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
packages/gql/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Run bun run generate to regenerate types for all platforms (TypeScript, Swift, Kotlin, Dart) from the GraphQL schema

Files:

  • packages/gql/src/type-android.graphql
packages/google/**/*.kt

📄 CodeRabbit inference engine (CLAUDE.md)

DO NOT add Android suffix to function names in the Android-only package, even for Android-specific APIs (e.g., use acknowledgePurchase() not acknowledgePurchaseAndroid())

Files:

  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingConverters.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
packages/apple/**/*.swift

📄 CodeRabbit inference engine (CLAUDE.md)

packages/apple/**/*.swift: iOS-specific functions MUST have IOS suffix (e.g., presentCodeRedemptionSheetIOS(), showManageSubscriptionsIOS())
Use Pascal case for acronyms at the beginning or middle of names (e.g., IapManager, IapPurchase), but ALL CAPS only when appearing as a suffix (e.g., ProductIAP, OpenIAP)

Files:

  • packages/apple/Sources/Models/Types.swift
packages/apple/Sources/Models/Types.swift

📄 CodeRabbit inference engine (CLAUDE.md)

DO NOT edit Types.swift in Sources/Models/ as it is auto-generated from the OpenIAP GraphQL schema; regenerate using ./scripts/generate-types.sh

Files:

  • packages/apple/Sources/Models/Types.swift
packages/apple/Sources/Models/**/*.swift

📄 CodeRabbit inference engine (CLAUDE.md)

OpenIAP official types in Sources/Models/ must match types defined at openiap.dev/docs/types

Files:

  • packages/apple/Sources/Models/Types.swift
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: iOS-specific functions must end with IOS suffix (e.g., clearTransactionIOS, getAppTransactionIOS)
Android-specific functions must end with Android suffix (e.g., acknowledgePurchaseAndroid, consumePurchaseAndroid)
Use action prefixes for function naming: get for retrieval, request for async operations, clear for removal, is/has for boolean checks, show/present for UI display, begin/finish/end for process control

Prefer interface for defining object shapes in TypeScript

Files:

  • packages/docs/src/pages/docs/types.tsx
  • packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/docs/**/*.{ts,tsx}: Use kebab-case for search modal IDs (e.g., id: 'request-products')
Modal state should be defined once at the app root level using Preact Signals (signal from '@preact/signals-react'), not instantiated multiple times
ALL components must fit within parent boundaries and never overflow outside parent containers; use overflow-hidden, break-words, and whitespace-nowrap as needed
Delete unused components, functions, and imports immediately; do not keep commented-out code or unused variables
ANY function that returns a Promise must be wrapped with void operator when used where a void return is expected (e.g., event handlers)

Files:

  • packages/docs/src/pages/docs/types.tsx
  • packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

packages/docs/**/*: Before committing, run npx prettier --write, npm run lint, bun run tsc or npm run typecheck, and npm run build to verify formatting, linting, types, and build success
Use conventional commit format with lowercase type prefix and lowercase description (e.g., feat: add user authentication)

Files:

  • packages/docs/src/pages/docs/types.tsx
  • packages/docs/src/pages/docs/updates/notes.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{ts,tsx,js,jsx}: Use camelCase for variable and function names
Use PascalCase for class and component names
Always use async/await for handling promises instead of .then() chains
Add JSDoc comments for public functions and exported APIs
Use const by default, let if reassignment is needed, avoid var

Files:

  • packages/docs/src/pages/docs/types.tsx
  • packages/docs/src/pages/docs/updates/notes.tsx
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify

Applied to files:

  • packages/gql/src/type-android.graphql
  • packages/google/openiap/build.gradle.kts
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/docs/src/pages/docs/updates/notes.tsx
  • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/Types.kt : DO NOT edit `openiap/src/main/Types.kt` as it is auto-generated from the GraphQL schema; regenerate it using `./scripts/generate-types.sh`

Applied to files:

  • packages/gql/src/type-android.graphql
  • packages/google/openiap/build.gradle.kts
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingConverters.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility

Applied to files:

  • packages/gql/src/type-android.graphql
  • packages/docs/src/pages/docs/updates/notes.tsx
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/Types.swift : DO NOT edit `Types.swift` in `Sources/Models/` as it is auto-generated from the OpenIAP GraphQL schema; regenerate using `./scripts/generate-types.sh`

Applied to files:

  • packages/gql/src/type-android.graphql
  • packages/apple/Sources/Models/Types.swift
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap/src/main/java/dev/hyo/openiap/utils/**/*.kt : Place reusable Kotlin helper functions in `openiap/src/main/java/dev/hyo/openiap/utils/`

Applied to files:

  • packages/google/openiap/build.gradle.kts
  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingConverters.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/**/*.kt : DO NOT add `Android` suffix to function names in the Android-only package, even for Android-specific APIs (e.g., use `acknowledgePurchase()` not `acknowledgePurchaseAndroid()`)

Applied to files:

  • packages/google/openiap/src/play/java/dev/hyo/openiap/OpenIapModule.kt
  • packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingConverters.kt
  • packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/Sources/Models/**/*.swift : OpenIAP official types in `Sources/Models/` must match types defined at [openiap.dev/docs/types](https://www.openiap.dev/docs/types)

Applied to files:

  • packages/apple/Sources/Models/Types.swift
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to **/*.{ts,tsx} : Android-specific functions must end with `Android` suffix (e.g., `acknowledgePurchaseAndroid`, `consumePurchaseAndroid`)

Applied to files:

  • packages/docs/src/pages/docs/types.tsx
🧬 Code graph analysis (3)
packages/apple/Sources/Models/Types.swift (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (1)
  • preorderPresaleEndTimeMillis (853-880)
packages/gql/src/generated/Types.kt (1)
  • preorderPresaleEndTimeMillis (920-947)
packages/docs/src/pages/docs/types.tsx (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (2)
  • code (1334-1356)
  • code (1886-1905)
packages/gql/src/generated/Types.kt (2)
  • code (1401-1423)
  • code (1953-1972)
packages/docs/src/pages/docs/updates/notes.tsx (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (2)
  • code (1334-1356)
  • code (1886-1905)
packages/gql/src/generated/Types.kt (2)
  • code (1401-1423)
  • code (1953-1972)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test Android
🔇 Additional comments (9)
packages/apple/Sources/Models/Types.swift (1)

379-388: Generated Swift types for Billing 8.1.0 fields are consistent with schema

PreorderDetailsAndroid, the optional preorderDetailsAndroid on ProductAndroidOneTimePurchaseOfferDetail, and isSuspendedAndroid on PurchaseAndroid all line up with the Kotlin and GraphQL definitions (names + String millis semantics and suspension behavior). Assuming this file was regenerated from the updated GraphQL schema (and not hand‑edited), the additions look correct and schema‑aligned. As per coding guidelines, keep updating this file only via ./scripts/generate-types.sh.

Also applies to: 420-426, 505-511

packages/docs/src/pages/docs/types.tsx (1)

373-384: Android docs for preorderDetailsAndroid and isSuspendedAndroid are clear and accurate

The updated Android docs correctly describe oneTimePurchaseOfferDetailsAndroid now including priceCurrencyCode and preorderDetailsAndroid with the two millis fields, and the isSuspendedAndroid description clearly warns not to grant entitlements and points to Billing 8.1.0 release notes. This keeps the public docs in sync with the new schema/runtime fields and should help avoid misuse on the client side.

Also applies to: 1181-1199

packages/docs/src/pages/docs/updates/notes.tsx (2)

508-523: LGTM - Version compatibility table accurately reflects the upgrade.

The table correctly shows v8.x as the current recommended version with the minSdk 23 and Kotlin 2.2.0 requirements, while maintaining v7.x and v6.x as supported versions with their respective deprecation dates.


544-577: LGTM - Recent Updates section provides comprehensive feature overview.

The section accurately documents the key features from Billing Library 8.1.0 including suspended subscriptions detection, pre-order support, SDK requirements, and the deprecated setSubscriptionReplacementMode() API.

packages/google/openiap/src/play/java/dev/hyo/openiap/utils/BillingConverters.kt (2)

30-36: LGTM - Clean extraction of pre-order details.

The null-safe chain correctly extracts preorderDetails from the one-time purchase offer and maps it to the PreorderDetailsAndroid data class. The conversion of Long timestamps to String is consistent with the GraphQL schema definition.


113-124: Reflection approach for backward compatibility is sound and aligns with Billing Library 8.1.0 design.

The use of reflection to call isSuspended() is appropriate since the method was introduced in Billing Library 8.1.0. The runCatching with getOrNull() safely handles older versions where this method doesn't exist.

Two considerations for future maintenance:

  1. Reflection incurs minor performance overhead on every purchase conversion
  2. Silent null return if Google changes the method signature in future versions

Consider adding a compile-time check or annotation to revisit this implementation when the minimum Billing Library version is bumped past 8.1.0.

packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (3)

849-880: LGTM - Auto-generated PreorderDetailsAndroid type is correctly structured.

The data class follows the established patterns in this file with proper fromJson/toJson serialization, __typename inclusion, and KDoc documentation explaining the Billing Library 8.1.0+ requirement.

Based on learnings, this file is auto-generated from the GraphQL schema via ./scripts/generate-types.sh.


987-1016: LGTM - preorderDetailsAndroid field correctly added to one-time purchase offer details.

The optional field with proper null-safe deserialization and serialization is consistent with the pattern used for other nested types in this file.


1255-1262: LGTM - Well-documented isSuspendedAndroid field with clear usage guidance.

The KDoc comment effectively communicates:

  1. What suspended means (payment method failure)
  2. What action developers should take (direct users to subscription center)
  3. Critical warning not to grant entitlements for suspended subscriptions
  4. Billing Library version requirement (8.1.0+)

Comment on lines +4 to +5
id("org.jetbrains.kotlin.android") version "2.2.0" apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.2.0" apply false
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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Jetpack Compose compiler extension versions support Kotlin 2.2.0 compatibility matrix

💡 Result:

Short answer: for Kotlin 2.2.0 you must use the Compose compiler that matches the Kotlin version — i.e. the Compose Compiler Gradle plugin version 2.2.0 (or the corresponding kotlin-compose-compiler plugin artifact 2.2.0 if not using the Gradle plugin). [1][2][3]

References:

  • Compose ⇄ Kotlin compatibility map (Kotlin 2.0+ → use Compose Compiler Gradle plugin). [1]
  • Compose Compiler Gradle plugin docs (plugin version = Kotlin version; example use with 2.0.0). [2]
  • Kotlin migration / Compose compiler docs (compiler moved into Kotlin repo; use matching 2.x compiler or kotlin-compose-compiler-plugin artifacts). [3]

🏁 Script executed:

cat -n packages/google/build.gradle.kts

Repository: hyodotdev/openiap

Length of output: 2164


Ensure Compose compiler version is set to 2.2.0 to match Kotlin 2.2.0

The Kotlin plugins are correctly aligned at 2.2.0. However, the Compose compiler version must also be 2.2.0—since Kotlin 2.0+, the Compose compiler is bundled in the Kotlin repository and versions must match. Verify that your COMPOSE_COMPILER_VERSION gradle property is set to 2.2.0 (lines 41-42 reference this property).

🤖 Prompt for AI Agents
In packages/google/build.gradle.kts around lines 4-5, the Kotlin plugin versions
are set to 2.2.0 but the Compose compiler Gradle property referenced later must
match; update the COMPOSE_COMPILER_VERSION Gradle property to "2.2.0" (or add it
if missing) so the Compose compiler version aligns with Kotlin 2.2.0, and ensure
any usages or references (e.g., lines 41-42) read that property.

- Format notes.tsx with prettier
- Update COMPOSE_COMPILER_VERSION to 2.2.0 to match Kotlin version
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ebe1e5 and d01bf4b.

📒 Files selected for processing (2)
  • packages/docs/src/pages/docs/updates/notes.tsx (7 hunks)
  • packages/google/gradle.properties (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: iOS-specific functions must end with IOS suffix (e.g., clearTransactionIOS, getAppTransactionIOS)
Android-specific functions must end with Android suffix (e.g., acknowledgePurchaseAndroid, consumePurchaseAndroid)
Use action prefixes for function naming: get for retrieval, request for async operations, clear for removal, is/has for boolean checks, show/present for UI display, begin/finish/end for process control

Prefer interface for defining object shapes in TypeScript

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/docs/**/*.{ts,tsx}: Use kebab-case for search modal IDs (e.g., id: 'request-products')
Modal state should be defined once at the app root level using Preact Signals (signal from '@preact/signals-react'), not instantiated multiple times
ALL components must fit within parent boundaries and never overflow outside parent containers; use overflow-hidden, break-words, and whitespace-nowrap as needed
Delete unused components, functions, and imports immediately; do not keep commented-out code or unused variables
ANY function that returns a Promise must be wrapped with void operator when used where a void return is expected (e.g., event handlers)

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

packages/docs/**/*: Before committing, run npx prettier --write, npm run lint, bun run tsc or npm run typecheck, and npm run build to verify formatting, linting, types, and build success
Use conventional commit format with lowercase type prefix and lowercase description (e.g., feat: add user authentication)

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{ts,tsx,js,jsx}: Use camelCase for variable and function names
Use PascalCase for class and component names
Always use async/await for handling promises instead of .then() chains
Add JSDoc comments for public functions and exported APIs
Use const by default, let if reassignment is needed, avoid var

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/**/*.kt : DO NOT add `Android` suffix to function names in the Android-only package, even for Android-specific APIs (e.g., use `acknowledgePurchase()` not `acknowledgePurchaseAndroid()`)
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to **/*.{ts,tsx} : Android-specific functions must end with `Android` suffix (e.g., `acknowledgePurchaseAndroid`, `consumePurchaseAndroid`)

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
🧬 Code graph analysis (1)
packages/docs/src/pages/docs/updates/notes.tsx (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (2)
  • code (1334-1356)
  • code (1886-1905)
packages/gql/src/generated/Types.kt (2)
  • code (1401-1423)
  • code (1953-1972)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test Android
🔇 Additional comments (4)
packages/google/gradle.properties (1)

34-37: Correct version alignment for Kotlin 2.2.0 upgrade.

The update of COMPOSE_COMPILER_VERSION to 2.2.0 correctly matches the Kotlin upgrade (2.0.21 → 2.2.0). The added comments accurately document that the Compose compiler has been bundled with Kotlin since version 2.0+, and the guidance that compiler and Kotlin versions should be aligned is sound.

packages/docs/src/pages/docs/updates/notes.tsx (3)

517-529: LGTM! Version compatibility table accurately updated.

The table correctly reflects the current state:

  • v8.x as the latest version with minSdk 23 and Kotlin 2.2.0 requirements
  • v7.x and v6.x as supported with deprecation timeline
  • Clear progression and compatibility information

This aligns with the library upgrade documented in the PR.


555-588: Comprehensive update summary for v8.1.

The Recent Updates section provides a clear, chronological overview of Google Play Billing Library v8.1 features. The information is consistent with the detailed announcement block above and adds useful context about deprecated APIs.

Note: The external link verification in the previous comment also covers the links in this section.


534-534: Accurate terminology correction.

Changing "External Purchase support" to "Alternative Billing support" for v6.x is more precise, as Google Play Billing Library v6.x specifically introduced Alternative Billing, while External Purchase is iOS terminology.

Comment thread packages/docs/src/pages/docs/updates/notes.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d01bf4b and 382bb90.

📒 Files selected for processing (1)
  • packages/docs/src/pages/docs/updates/notes.tsx (7 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: iOS-specific functions must end with IOS suffix (e.g., clearTransactionIOS, getAppTransactionIOS)
Android-specific functions must end with Android suffix (e.g., acknowledgePurchaseAndroid, consumePurchaseAndroid)
Use action prefixes for function naming: get for retrieval, request for async operations, clear for removal, is/has for boolean checks, show/present for UI display, begin/finish/end for process control

Prefer interface for defining object shapes in TypeScript

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/docs/**/*.{ts,tsx}: Use kebab-case for search modal IDs (e.g., id: 'request-products')
Modal state should be defined once at the app root level using Preact Signals (signal from '@preact/signals-react'), not instantiated multiple times
ALL components must fit within parent boundaries and never overflow outside parent containers; use overflow-hidden, break-words, and whitespace-nowrap as needed
Delete unused components, functions, and imports immediately; do not keep commented-out code or unused variables
ANY function that returns a Promise must be wrapped with void operator when used where a void return is expected (e.g., event handlers)

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
packages/docs/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

packages/docs/**/*: Before committing, run npx prettier --write, npm run lint, bun run tsc or npm run typecheck, and npm run build to verify formatting, linting, types, and build success
Use conventional commit format with lowercase type prefix and lowercase description (e.g., feat: add user authentication)

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{ts,tsx,js,jsx}: Use camelCase for variable and function names
Use PascalCase for class and component names
Always use async/await for handling promises instead of .then() chains
Add JSDoc comments for public functions and exported APIs
Use const by default, let if reassignment is needed, avoid var

Files:

  • packages/docs/src/pages/docs/updates/notes.tsx
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to **/*.{ts,tsx} : Android-specific functions must end with `Android` suffix (e.g., `acknowledgePurchaseAndroid`, `consumePurchaseAndroid`)

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/docs/**/*.{md,mdx} : Use kebab-case for URL anchors (e.g., `#fetch-products`, `#get-app-transaction-ios`)

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/google/openiap-versions.json : To update OpenIAP GraphQL types in the Android library, edit the `gql` field in `openiap-versions.json`, then run `./scripts/generate-types.sh` and compile to verify

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
📚 Learning: 2025-12-06T20:15:59.223Z
Learnt from: CR
Repo: hyodotdev/openiap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T20:15:59.223Z
Learning: Applies to packages/apple/openiap-versions.json : To update OpenIAP GraphQL types in the iOS/macOS library, edit the `gql` field in `openiap-versions.json`, run `./scripts/generate-types.sh`, and run `swift test` to verify compatibility

Applied to files:

  • packages/docs/src/pages/docs/updates/notes.tsx
🧬 Code graph analysis (1)
packages/docs/src/pages/docs/updates/notes.tsx (2)
packages/google/openiap/src/main/java/dev/hyo/openiap/Types.kt (2)
  • code (1334-1356)
  • code (1886-1905)
packages/gql/src/generated/Types.kt (2)
  • code (1401-1423)
  • code (1953-1972)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test Android
🔇 Additional comments (2)
packages/docs/src/pages/docs/updates/notes.tsx (2)

22-107: No issues found. The internal documentation anchors (#purchase-platform and #product-platform) are correctly defined in packages/docs/src/pages/docs/types.tsx at lines 863 and 293 respectively. The Kotlin code example is accurate: all API field names (isSuspendedAndroid, preorderDetailsAndroid, preorderReleaseTimeMillis, preorderPresaleEndTimeMillis) match the actual type definitions in the codebase, and the optional chaining and type conversions are valid.


1-705: Run pre-commit checks before committing.

Ensure these checks pass per the coding guidelines for packages/docs/**/*:

  • npx prettier --write (code formatting)
  • npm run lint (linting)
  • bun run tsc or npm run typecheck (type checking)
  • npm run build (build verification)

Comment thread packages/docs/src/pages/docs/updates/notes.tsx
@hyochan hyochan merged commit c6b5b32 into main Dec 9, 2025
5 checks passed
@hyochan hyochan deleted the feat/android-billing-8.1.0 branch December 9, 2025 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🤖 android Related to android 🎯 feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant