-
-
Notifications
You must be signed in to change notification settings - Fork 689
feat: add Google Play Billing 8.3.0 External Payments support #3117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add External Payments program (Japan only) with side-by-side payment choice - Add developerProvidedBillingListenerAndroid for handling external payment selection - Add enableBillingProgramAndroid to InitConnectionConfig for cleaner setup - Add DeveloperBillingOptionParamsAndroid and DeveloperBillingLaunchModeAndroid types - Update openiap versions (gql 1.3.10, google 1.3.19, apple 1.3.8) - Add documentation and tests for External Payments API
|
Warning Rate limit exceeded@hyochan has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 50 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds Android External Payments (Developer Provided Billing) support: native OpenIAP listener wiring, new public listener APIs and types, init-time billing program enablement, TypeScript API wrappers, tests, docs, and version bumps for OpenIAP deps. Changes
Sequence Diagram(s)sequenceDiagram
participant App as App Code
participant IAP as React Native IAP
participant Nitro as Nitro Bridge (HybridRnIap)
participant OpenIAP as OpenIAP Library
participant GP as Google Play Billing
rect rgba(230,245,255,0.4)
Note over App,IAP: Init + enable external-payments
App->>IAP: initConnection({ enableBillingProgramAndroid: 'external-payments' })
IAP->>Nitro: initConnection(config)
Nitro->>OpenIAP: init with enableBillingProgram
Nitro->>Nitro: register OpenIapDeveloperProvidedBillingListener
end
rect rgba(230,245,255,0.15)
Note over App,IAP: Listener registration
App->>IAP: developerProvidedBillingListenerAndroid(listener)
IAP->>Nitro: addDeveloperProvidedBillingListenerAndroid(listener)
Nitro->>Nitro: store listener
end
rect rgba(200,230,255,0.15)
Note over App,GP: Purchase flow (external payments)
App->>IAP: requestPurchase({ developerBillingOption: {...} })
IAP->>Nitro: requestPurchase(params)
Nitro->>OpenIAP: launch external billing flow
OpenIAP->>GP: show developer/payment option
GP-->>OpenIAP: user selects external payment
OpenIAP->>Nitro: onDeveloperProvidedBilling(token)
Nitro->>IAP: sendDeveloperProvidedBilling({ externalTransactionToken: token })
IAP->>App: invoke listener(details)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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. Comment |
Summary of ChangesHello @hyochan, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request integrates the latest Google Play Billing Library 8.3.0 features, specifically the External Payments program, into the system. This enables applications to present users in Japan with a direct choice between Google Play's billing and an external payment method. The changes involve introducing new listeners and configuration options for managing this payment flow, updating core dependencies, and providing clear documentation and tests for developers to adopt this new functionality. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
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 8.3.0's External Payments program, which is a significant feature addition. The changes are comprehensive, covering native Android implementation, TypeScript definitions, tests, and extensive documentation. The code is well-structured and the documentation is clear. I've found one potential issue in the native Android code regarding a redundant call, which I've detailed in a specific comment. Overall, this is a great contribution.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3117 +/- ##
==========================================
+ Coverage 64.68% 64.93% +0.24%
==========================================
Files 9 9
Lines 1665 1691 +26
Branches 564 569 +5
==========================================
+ Hits 1077 1098 +21
- Misses 582 587 +5
Partials 6 6
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/index.ts (2)
121-129:developerBillingOptionfromrequestPurchaseis not forwarded to native on AndroidBoth
RequestPurchaseAndroidPropsandRequestSubscriptionAndroidProps(src/types.ts:977, 1051) include thedeveloperBillingOptionfield for External Payments support (8.3.0+), but therequestPurchasefunction (lines 1224–1271) does not forward it toandroidPayload. Similarly,NitroRequestPurchaseAndroid(src/specs/RnIap.nitro.ts:121) does not include this field.This means callers can pass
developerBillingOptionas documented in the release notes and type definitions, but it will be silently dropped before reachingIAP.instance.requestPurchase.To support External Payments as documented:
- Add
developerBillingOption?: DeveloperBillingOptionParamsAndroid | null;toNitroRequestPurchaseAndroidinsrc/specs/RnIap.nitro.ts.- Forward
androidRequest.developerBillingOptiontoandroidPayload.developerBillingOptionin the Android branch for both subscription and in-app purchase flows.- Verify the field name and type match the native/OpenIAP side expectations.
2350-2353: ExportedBillingProgramAndroidunion is missing'external-payments'The public
BillingProgramAndroidtype exported fromsrc/index.ts(lines 2350–2353) only includes:export type BillingProgramAndroid = | 'unspecified' | 'external-content-link' | 'external-offer';However:
- The canonical
src/types.tsdefinition includes'external-payments'.- Tests call
enableBillingProgramAndroid('external-payments').- Docs recommend and demonstrate the same string literal.
This mismatch causes TypeScript consumers to get type errors when using the new program value, even though it's supported at the bridge level. Update the exported union to include:
export type BillingProgramAndroid = | 'unspecified' | 'external-content-link' | 'external-offer' | 'external-payments';Longer-term, consider aliasing the generated type from
src/types.tsinstead of hardcoding the union to avoid similar omissions on future openiap updates.src/types.ts (1)
1-4: Remove duplicate type definitions; import fromsrc/types.tsinstead.
DeveloperProvidedBillingDetailsAndroidis defined in three locations (src/types.ts, src/index.ts, and src/specs/RnIap.nitro.ts). Per the coding guidelines, types should be imported from src/types.ts rather than defined ad-hoc in other files. Since src/index.ts already exports everything from src/types.ts (line 65), the local definition at line 412 is redundant and should be removed. Similarly, src/specs/RnIap.nitro.ts should import this type from src/types.ts instead of defining it locally.
🧹 Nitpick comments (4)
docs/docs/api/methods/listeners.md (1)
496-580: Docs fordeveloperProvidedBillingListenerAndroidmatch implementationThe new section correctly documents platform (Android), version (8.3.0+), Japan-only scope, the need to enable
external-paymentsbeforeinitConnection, and theexternalTransactionTokenpayload. Looks accurate and consistent with the code and tests; you might optionally add a link to the alternative billing guide’s External Payments section for deeper context.src/specs/RnIap.nitro.ts (1)
48-60: Nitro spec additions align with External Payments, but duplicate a generated type
- Extending
BillingProgramAndroidwith'external-payments'and introducingDeveloperBillingLaunchModeAndroid/DeveloperProvidedBillingDetailsAndroidare consistent with the new External Payments flow and the public JS API.- However,
DeveloperProvidedBillingDetailsAndroidnow exists in three places:src/types.ts(generated), this Nitro spec, andsrc/index.ts. To avoid drift when openiap regeneratessrc/types.ts, consider aliasing the generated type here instead of re-declaring the interface.For example (conceptually):
import type { DeveloperProvidedBillingDetailsAndroid as GeneratedDeveloperProvidedBillingDetailsAndroid, } from '../types'; export interface DeveloperProvidedBillingDetailsAndroid extends GeneratedDeveloperProvidedBillingDetailsAndroid {}Also, since this file changed, remember to regenerate Nitro bridge files (
yarn specs) so the native bridge picks up the new listener and billing program values.Also applies to: 331-342, 964-989
src/index.ts (1)
412-419: Avoid re-declaringDeveloperProvidedBillingDetailsAndroidhere
DeveloperProvidedBillingDetailsAndroidis already defined insrc/types.ts(and also insrc/specs/RnIap.nitro.ts). Re-declaring it insrc/index.tsintroduces a third copy that can silently drift if the generated types add fields in future openiap updates.Instead, import and re‑export the canonical type from
./types:import type {DeveloperProvidedBillingDetailsAndroid} from './types'; // (re-export is already covered by `export * from './types';`)and remove the local
export interface DeveloperProvidedBillingDetailsAndroid { ... }block so there’s a single source of truth.android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (1)
1578-1583: Remove unused functionmapDeveloperBillingLaunchModeor add a TODO explaining its intended use.This private function is defined but never called anywhere in the codebase. Either remove it, or if it's reserved for future implementation (e.g., handling
developerBillingOptionin the purchase flow), add a TODO comment explaining the planned usage to clarify intent.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.ktdocs/blog/2025-12-28-release-14.6.4.mddocs/docs/api/methods/listeners.mddocs/docs/guides/alternative-billing.mdopeniap-versions.jsonsrc/__tests__/index.test.tssrc/index.tssrc/specs/RnIap.nitro.tssrc/types.ts
🧰 Additional context used
📓 Path-based instructions (6)
src/types.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Never edit src/types.ts manually; it is generated. Import canonical types from this file instead of defining ad‑hoc interfaces.
Files:
src/types.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
When declaring API params/results in TS modules, import canonical types from src/types.ts rather than creating ad‑hoc interfaces.
Files:
src/types.tssrc/specs/RnIap.nitro.tssrc/index.tssrc/__tests__/index.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use type-only imports when importing types (import type).
Files:
src/types.tssrc/specs/RnIap.nitro.tssrc/index.tssrc/__tests__/index.test.ts
{src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}
📄 CodeRabbit inference engine (CLAUDE.md)
{src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}: Prefer using isUserCancelledError() and getUserFriendlyErrorMessage() with normalized ErrorCode when handling purchase errors.
Use Platform.OS checks for platform-specific logic in React Native code.
Files:
src/types.tssrc/specs/RnIap.nitro.tssrc/index.tssrc/__tests__/index.test.ts
**/*.nitro.ts
📄 CodeRabbit inference engine (CLAUDE.md)
After modifying any .nitro.ts interface files, regenerate Nitro bridge files (yarn specs).
Files:
src/specs/RnIap.nitro.ts
{ios/**/*.swift,android/src/main/java/**/*.kt}
📄 CodeRabbit inference engine (CLAUDE.md)
Follow the native class function ordering: (1) properties/init, (2) public cross-platform methods, (3) platform-specific public methods (IOS/Android suffix), (4) event listener methods, (5) private helpers.
Files:
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
🧠 Learnings (5)
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to {example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}} : In useIAP hook usage, do not expect returned data from methods that return Promise<void>; consume state from the hook instead.
Applied to files:
docs/docs/api/methods/listeners.mdsrc/types.tssrc/__tests__/index.test.ts
📚 Learning: 2025-09-14T00:13:04.055Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3002
File: docs/docs/getting-started/setup-ios.md:55-60
Timestamp: 2025-09-14T00:13:04.055Z
Learning: The validateReceipt function from useIAP hook in react-native-iap expects a transaction identifier as parameter, which is accessed via purchase.id (not purchase.productId). This is confirmed by the maintainer hyochan and aligns with the library's migration from purchase.transactionId to purchase.id.
Applied to files:
docs/docs/api/methods/listeners.mdsrc/types.ts
📚 Learning: 2025-09-18T16:45:10.582Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3015
File: src/types.ts:137-166
Timestamp: 2025-09-18T16:45:10.582Z
Learning: The types in src/types.ts are auto-generated from openiap-gql1.0.6. Breaking changes in mutation return types (like acknowledgePurchaseAndroid returning Promise<boolean>, finishTransaction returning Promise<void>, etc.) originate from updates to this external GraphQL schema generator, not manual refactoring.
Applied to files:
src/types.tssrc/specs/RnIap.nitro.tssrc/index.tsopeniap-versions.jsonsrc/__tests__/index.test.ts
📚 Learning: 2025-09-13T01:07:18.841Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 2999
File: android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt:644-660
Timestamp: 2025-09-13T01:07:18.841Z
Learning: In Android IAP error handling: purchaseToken and productId are distinct properties - purchaseToken identifies a completed purchase transaction (should be null in error cases), while productId is the product SKU for context
Applied to files:
src/types.tssrc/specs/RnIap.nitro.ts
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to {src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}} : Prefer using isUserCancelledError() and getUserFriendlyErrorMessage() with normalized ErrorCode when handling purchase errors.
Applied to files:
src/types.ts
🧬 Code graph analysis (5)
src/types.ts (2)
src/index.ts (2)
BillingProgramAndroid(2350-2353)DeveloperProvidedBillingDetailsAndroid(412-419)src/specs/RnIap.nitro.ts (3)
BillingProgramAndroid(49-53)DeveloperBillingLaunchModeAndroid(56-59)DeveloperProvidedBillingDetailsAndroid(335-342)
src/specs/RnIap.nitro.ts (2)
src/index.ts (2)
BillingProgramAndroid(2350-2353)DeveloperProvidedBillingDetailsAndroid(412-419)src/types.ts (3)
BillingProgramAndroid(72-72)DeveloperBillingLaunchModeAndroid(112-112)DeveloperProvidedBillingDetailsAndroid(133-140)
src/index.ts (3)
src/specs/RnIap.nitro.ts (2)
RnIap(542-1073)DeveloperProvidedBillingDetailsAndroid(335-342)src/types.ts (1)
DeveloperProvidedBillingDetailsAndroid(133-140)src/utils/debug.ts (1)
RnIapConsole(18-49)
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (3)
src/index.ts (1)
DeveloperProvidedBillingDetailsAndroid(412-419)src/specs/RnIap.nitro.ts (1)
DeveloperProvidedBillingDetailsAndroid(335-342)src/types.ts (1)
DeveloperProvidedBillingDetailsAndroid(133-140)
src/__tests__/index.test.ts (2)
android/src/main/java/com/margelo/nitro/iap/RnIapLog.kt (1)
warn(26-28)ios/RnIapLog.swift (1)
warn(34-34)
🪛 GitHub Actions: CI - Library Build
src/types.ts
[error] 1-1: yarn generate:types failed. Exit code 1 during type generation (OpenIAP types update caused the step to fail). Command: 'yarn generate:types'.
⏰ 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: build-android
🔇 Additional comments (18)
openiap-versions.json (1)
2-4: Version bumps look consistent with release notesThe updated openiap versions for apple, google, and gql are straightforward and align with the documented 14.6.4 release; no code-level concerns.
docs/blog/2025-12-28-release-14.6.4.md (1)
1-118: Release notes accurately describe 14.6.4 feature surfaceThe blog post’s description of External Payments, new listener,
enableBillingProgramAndroid, and openiap version bumps matches the code and test changes. The usage example is consistent with the public API shape exposed fromsrc/index.tsand the Nitro spec.docs/docs/guides/alternative-billing.md (1)
318-390: External Payments guide section is clear and consistentThe new External Payments section (8.3.0+, Japan only) clearly explains setup, listener usage, and the
developerBillingOptionshape, and its comparison table vs User Choice Billing matches the API surface. This will rely onrequestPurchasecorrectly forwardingdeveloperBillingOptionto native (see src/index.ts comment), but the guide itself is coherent.src/__tests__/index.test.ts (1)
1481-1525: Good coverage for new Android External Payments APIsThe new tests correctly cover:
- Non-Android behavior for
developerProvidedBillingListenerAndroid(warn + no-op unsubscribe).- Android path: listener registration, payload forwarding of
externalTransactionToken, and proper removal.enableBillingProgramAndroid('external-payments')forwarding the new program value to the Nitro layer.This gives solid regression protection for the new listener and billing program support.
Also applies to: 1541-1547
src/index.ts (1)
374-464: NewdeveloperProvidedBillingListenerAndroidmatches existing listener patternsThe implementation mirrors the patterns used for
userChoiceBillingListenerAndroidand the purchase listeners:
- Android-only guard with clear warning message.
- WeakMap to keep track of wrapped Nitro listeners for safe removal.
- Graceful handling of Nitro-not-installed errors with an inert listener and informative warning.
Functionally this looks correct and matches the behavior covered in the new tests.
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (6)
41-42: LGTM!New imports correctly aliased for OpenIAP Developer Billing types, following the same aliasing pattern used for other OpenIAP imports in this file.
83-83: LGTM!Listener collection follows the same pattern as
userChoiceBillingListenersAndroidon line 82, maintaining consistency.
174-186: LGTM!The Developer Provided Billing listener registration follows the same pattern as the other listeners (purchase update, purchase error, user choice billing). The error handling with
runCatchingandonFailureis consistent with the existing implementation.
193-210: LGTM!The billing program is correctly enabled before
initConnectionas required by the API. The config mapping properly passesenableBillingProgramAndroidto the OpenIAP initialization config.
1453-1470: LGTM!The listener management methods follow the same thread-safe pattern as
userChoiceBillingListenersAndroid:
synchronizedblocks protect concurrent accesssendDeveloperProvidedBillingiterates and dispatches safelyBased on coding guidelines, the function ordering is correct (event listener methods section).
1574-1576: LGTM!The new
EXTERNAL_PAYMENTScase correctly maps toOpenIapBillingProgramAndroid.ExternalPayments, completing the billing program mapping.src/types.ts (7)
68-72: Newexternal-paymentsvalue aligns with Nitro spec.The updated
BillingProgramAndroidtype now includes'external-payments', which matches the definition insrc/specs/RnIap.nitro.ts(lines 48-52). The documentation correctly notes the 8.3.0 version requirement.
107-140: New External Payments types are well-documented.The new types
DeveloperBillingLaunchModeAndroid,DeveloperBillingOptionParamsAndroid, andDeveloperProvidedBillingDetailsAndroidinclude clear JSDoc comments with version requirements (8.3.0+). The structure aligns with the Nitro spec definitions.
308-308: LGTM!The new
'developer-provided-billing-android'event type is correctly added to theIapEventunion type.
324-334: LGTM!The
enableBillingProgramAndroidfield is properly documented with available programs and version requirements. The nullable union type(BillingProgramAndroid | null)follows the existing pattern used foralternativeBillingModeAndroid.
975-980: LGTM!The
developerBillingOptionfield is consistently added to bothRequestPurchaseAndroidPropsandRequestSubscriptionAndroidPropswith identical documentation, enabling the External Payments flow for both purchase types.Also applies to: 1063-1068
1150-1157: LGTM!The
developerProvidedBillingAndroidsubscription event is well-documented, explaining when it fires and what data it contains.
1448-1448: LGTM!The subscription args map entry correctly uses
neversince the event doesn't require arguments, consistent with other subscription events.
…illing - Add 'external-payments' option to Android billing mode selector - Add developerProvidedBillingListenerAndroid setup for handling when user selects developer billing in Japan - Add handleAndroidExternalPayments handler with developerBillingOption - Add External Payments Token display section - Update info card and status text for new mode - Update documentation comments
There was a problem hiding this 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
🧹 Nitpick comments (1)
example/screens/AlternativeBilling.tsx (1)
459-503: Consider usingisUserCancelledError()for consistent error handling.The error handling at line 494 uses direct string comparison (
error.code !== 'user-cancelled'). Per coding guidelines, prefer usingisUserCancelledError()with normalizedErrorCodewhen handling purchase errors.This is consistent with the existing pattern in
onPurchaseError(line 146), so if you update one, consider updating both for consistency.🔎 Proposed fix
Import the helper:
import { useIAP, requestPurchase, initConnection, endConnection, presentExternalPurchaseLinkIOS, isBillingProgramAvailableAndroid, createBillingProgramReportingDetailsAndroid, launchExternalLinkAndroid, developerProvidedBillingListenerAndroid, + isUserCancelledError, type Product, ...Then update the error check:
- if (error.code !== 'user-cancelled') { + if (!isUserCancelledError(error)) { setPurchaseResult(`❌ Error: ${error.message}`); Alert.alert('Error', error.message); } else {
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.ktexample/screens/AlternativeBilling.tsxsrc/types.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use type-only imports when importing types (import type).
Files:
example/screens/AlternativeBilling.tsxsrc/types.ts
{example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}
📄 CodeRabbit inference engine (CLAUDE.md)
{example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}: In useIAP hook usage, do not expect returned data from methods that return Promise; consume state from the hook instead.
Do not call parseErrorStringToJsonObj() in app/user code; errors are already normalized by the library.
Files:
example/screens/AlternativeBilling.tsx
{src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}
📄 CodeRabbit inference engine (CLAUDE.md)
{src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}}: Prefer using isUserCancelledError() and getUserFriendlyErrorMessage() with normalized ErrorCode when handling purchase errors.
Use Platform.OS checks for platform-specific logic in React Native code.
Files:
example/screens/AlternativeBilling.tsxsrc/types.ts
src/types.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Never edit src/types.ts manually; it is generated. Import canonical types from this file instead of defining ad‑hoc interfaces.
Files:
src/types.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
When declaring API params/results in TS modules, import canonical types from src/types.ts rather than creating ad‑hoc interfaces.
Files:
src/types.ts
{ios/**/*.swift,android/src/main/java/**/*.kt}
📄 CodeRabbit inference engine (CLAUDE.md)
Follow the native class function ordering: (1) properties/init, (2) public cross-platform methods, (3) platform-specific public methods (IOS/Android suffix), (4) event listener methods, (5) private helpers.
Files:
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
🧠 Learnings (6)
📓 Common learnings
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3015
File: src/types.ts:137-166
Timestamp: 2025-09-18T16:45:10.582Z
Learning: The types in src/types.ts are auto-generated from openiap-gql1.0.6. Breaking changes in mutation return types (like acknowledgePurchaseAndroid returning Promise<boolean>, finishTransaction returning Promise<void>, etc.) originate from updates to this external GraphQL schema generator, not manual refactoring.
📚 Learning: 2025-09-18T16:45:10.582Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3015
File: src/types.ts:137-166
Timestamp: 2025-09-18T16:45:10.582Z
Learning: The types in src/types.ts are auto-generated from openiap-gql1.0.6. Breaking changes in mutation return types (like acknowledgePurchaseAndroid returning Promise<boolean>, finishTransaction returning Promise<void>, etc.) originate from updates to this external GraphQL schema generator, not manual refactoring.
Applied to files:
example/screens/AlternativeBilling.tsxsrc/types.ts
📚 Learning: 2025-09-14T00:13:04.055Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 3002
File: docs/docs/getting-started/setup-ios.md:55-60
Timestamp: 2025-09-14T00:13:04.055Z
Learning: The validateReceipt function from useIAP hook in react-native-iap expects a transaction identifier as parameter, which is accessed via purchase.id (not purchase.productId). This is confirmed by the maintainer hyochan and aligns with the library's migration from purchase.transactionId to purchase.id.
Applied to files:
example/screens/AlternativeBilling.tsxsrc/types.ts
📚 Learning: 2025-09-13T01:07:18.841Z
Learnt from: hyochan
Repo: hyochan/react-native-iap PR: 2999
File: android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt:644-660
Timestamp: 2025-09-13T01:07:18.841Z
Learning: In Android IAP error handling: purchaseToken and productId are distinct properties - purchaseToken identifies a completed purchase transaction (should be null in error cases), while productId is the product SKU for context
Applied to files:
example/screens/AlternativeBilling.tsxsrc/types.ts
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to {example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}} : In useIAP hook usage, do not expect returned data from methods that return Promise<void>; consume state from the hook instead.
Applied to files:
src/types.ts
📚 Learning: 2025-10-02T19:35:19.667Z
Learnt from: CR
Repo: hyochan/react-native-iap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T19:35:19.667Z
Learning: Applies to {src/**/*.{ts,tsx},example/**/*.{ts,tsx},example-expo/**/*.{ts,tsx}} : Prefer using isUserCancelledError() and getUserFriendlyErrorMessage() with normalized ErrorCode when handling purchase errors.
Applied to files:
src/types.ts
🧬 Code graph analysis (3)
example/screens/AlternativeBilling.tsx (3)
src/index.ts (2)
developerProvidedBillingListenerAndroid(421-464)DeveloperProvidedBillingDetailsAndroid(412-419)src/types.ts (1)
DeveloperProvidedBillingDetailsAndroid(143-150)src/specs/RnIap.nitro.ts (1)
DeveloperProvidedBillingDetailsAndroid(335-342)
src/types.ts (2)
src/specs/RnIap.nitro.ts (3)
BillingProgramAndroid(49-53)DeveloperBillingLaunchModeAndroid(56-59)DeveloperProvidedBillingDetailsAndroid(335-342)src/index.ts (2)
BillingProgramAndroid(2350-2353)DeveloperProvidedBillingDetailsAndroid(412-419)
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (3)
src/types.ts (1)
DeveloperProvidedBillingDetailsAndroid(143-150)src/specs/RnIap.nitro.ts (1)
DeveloperProvidedBillingDetailsAndroid(335-342)src/index.ts (1)
DeveloperProvidedBillingDetailsAndroid(412-419)
⏰ 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: build-android
🔇 Additional comments (15)
example/screens/AlternativeBilling.tsx (4)
25-32: LGTM! Type-only imports used correctly.The imports correctly use type-only imports for
DeveloperProvidedBillingDetailsAndroidas per coding guidelines.
164-194: LGTM! Proper listener lifecycle management.The
developerProvidedBillingListenerAndroidsetup is well-structured:
- Platform check for Android-only execution
- Proper cleanup via
subscription.remove()in the return- Empty dependency array is appropriate since this listener should only be registered once
791-813: LGTM! External Payments token display section.Good UX for displaying the external transaction token with appropriate warnings about the 24-hour reporting requirement and clear token functionality.
883-902: LGTM! External Payments mode option added to modal.The mode selector option for External Payments is well-integrated with appropriate labeling indicating the Japan-specific availability and the side-by-side dialog behavior.
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt (6)
41-41: LGTM! Import added for OpenIapDeveloperProvidedBillingListener.Required import for the new External Payments listener functionality.
82-82: LGTM! Listener list follows established pattern.The
developerProvidedBillingListenersAndroidlist matches the structure ofuserChoiceBillingListenersAndroid, maintaining consistency.
173-185: LGTM! Developer Provided Billing listener wiring.The listener setup correctly:
- Follows the same error-handling pattern as other listeners (
runCatchingwithonFailurelogging)- Maps the OpenIAP details to the Nitro type
- Dispatches via
sendDeveloperProvidedBilling
193-204: LGTM! Billing program enablement via config.The
enableBillingProgramAndroidis correctly mapped from the config and passed toOpenIapInitConnectionConfig. This aligns with the documented "cleaner setup" approach and addresses the previous review feedback about redundant calls.
1447-1464: LGTM! Add/remove/send methods for developer provided billing.The implementation correctly uses
synchronizedblocks for thread safety, consistent with theuserChoiceBillinglistener pattern. The method signatures match the spec interface.
1563-1569: LGTM! EXTERNAL_PAYMENTS mapping added.The
mapBillingProgramfunction correctly maps the newEXTERNAL_PAYMENTSenum value toOpenIapBillingProgramAndroid.ExternalPayments.src/types.ts (5)
1-4: Auto-generated file — changes appear consistent with schema updates.Per learnings, this file is auto-generated from openiap-gql. The new types (
DeveloperProvidedBillingDetailsAndroid,DeveloperBillingLaunchModeAndroid,DeveloperBillingOptionParamsAndroid) and updated interfaces align with the External Payments feature additions.
117-150: LGTM! New External Payments types added.The new types for Developer Billing support are well-documented:
DeveloperBillingLaunchModeAndroid- launch mode optionsDeveloperBillingOptionParamsAndroid- parameters for purchase flowDeveloperProvidedBillingDetailsAndroid- callback details with external transaction tokenVersion availability (8.3.0+) is clearly noted in the JSDoc comments.
334-340: LGTM! enableBillingProgramAndroid added to InitConnectionConfig.The optional
enableBillingProgramAndroidproperty allows cleaner initialization without a separateenableBillingProgramAndroid()call, as documented in the PR objectives.
971-986: LGTM! developerBillingOption added to purchase request props.Both
RequestPurchaseAndroidPropsandRequestSubscriptionAndroidPropscorrectly include the optionaldeveloperBillingOptionparameter for enabling the External Payments flow during purchase.Also applies to: 1046-1074
1143-1163: LGTM! Subscription interface updated for developer provided billing.The
developerProvidedBillingAndroidsubscription event is properly documented, noting the 8.3.0+ availability and the purpose (receiving externalTransactionToken when user selects developer billing).
The canonical type with 'external-payments' is in types.ts (auto-generated from openiap-gql). Import it instead of redefining locally.
Summary by CodeRabbit
New Features
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.