Skip to content
This repository was archived by the owner on Apr 26, 2026. It is now read-only.

feat: sync with openiap v1.3.14 (billing library 8.0+ features)#3127

Merged
hyochan merged 4 commits into
mainfrom
feat/openiap-sync-1.3.14
Jan 18, 2026
Merged

feat: sync with openiap v1.3.14 (billing library 8.0+ features)#3127
hyochan merged 4 commits into
mainfrom
feat/openiap-sync-1.3.14

Conversation

@hyochan

@hyochan hyochan commented Jan 18, 2026

Copy link
Copy Markdown
Owner

Summary

Syncs with OpenIAP v1.3.14 bringing Google Play Billing Library 8.0+ features and iOS WWDC 2025 enhancements.

Android (Billing Library 8.0+)

  • Add productStatusAndroid field to products - explains why a product couldn't be fetched (ok, not-found, no-offers-available)
  • Add includeSuspended option to getAvailablePurchases - include suspended subscriptions (8.1+)
  • Add isSuspendedAndroid field to purchases
  • Add SubResponseCodeAndroid for granular error information

iOS (WWDC 2025)

  • Add introductoryOfferEligibility - override system-determined eligibility (iOS 15+, back-deployed)
  • Add promotionalOfferJWS - new JWS format for promotional offers (iOS 15+, back-deployed)
  • Add winBackOffer - win-back offers for churned subscribers (iOS 18+)
  • Add 'win-back' to SubscriptionOfferTypeIOS

Changes

  • Update openiap-versions.json (gql: 1.3.14, apple: 1.3.12, google: 1.3.25)
  • Regenerate TypeScript types from OpenIAP
  • Update Android native code (HybridRnIap.kt)
  • Update iOS native code (HybridRnIap.swift)
  • Update Nitro spec (RnIap.nitro.ts)
  • Update type-bridge for productStatusAndroid
  • Add release blog post
  • Update llms.txt with new API documentation

Test plan

  • Verify Android product fetch returns productStatusAndroid field
  • Verify getAvailablePurchases({ android: { includeSuspended: true }}) works
  • Verify iOS subscription with winBackOffer works (iOS 18+)
  • Verify iOS subscription with promotionalOfferJWS works (iOS 15+)
  • Run yarn typecheck - passes
  • Run yarn test - passes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Android productStatus field indicating fetch result (ok, not-found, no-offers-available, unknown)
    • Option to include suspended Android subscriptions in purchase listings
    • iOS: win-back offers, promotional JWS offers, and introductory-offer-eligibility override
    • Granular Android billing sub-response codes
  • Documentation

    • Updated guides and release notes describing Android product status, suspended subscriptions, iOS offer fields, and billing result details
    • Troubleshooting/docs updated to use useIAP({ onPurchaseError }) with connected and initConnection usage

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

- Update openiap-versions.json (gql: 1.3.14, apple: 1.3.12, google: 1.3.25)
- Regenerate TypeScript types from OpenIAP
- Add productStatusAndroid to NitroProduct (8.0+)
- Add includeSuspended option to getAvailablePurchases (8.1+)
- Add new iOS types: PromotionalOfferJwsInputIOS, WinBackOfferInputIOS
- Add RequestSubscriptionIosProps fields: introductoryOfferEligibility, promotionalOfferJWS, winBackOffer
- Add SubResponseCodeAndroid for granular error info (8.0+)
- Add BillingResultAndroid with subResponseCode
- Add 'win-back' to SubscriptionOfferTypeIOS
- Update llms.txt with new API docs
- Add release blog post for v14.8.0

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jan 18, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@hyochan has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 31 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

📥 Commits

Reviewing files that changed from the base of the PR and between 2984378 and 9d2a2d8.

📒 Files selected for processing (2)
  • docs/blog/2026-01-19-release-14.7.3-billing-library-8.md
  • docs/static/llms.txt

Note

Other AI code review bot(s) detected

CodeRabbit 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.

📝 Walkthrough

Walkthrough

Adds Android product status and suspended-subscription handling plus iOS subscription offer fields; updates type definitions, Nitro specs, Android/iOS bridge mappings, docs, and OpenIAP dependency versions.

Changes

Cohort / File(s) Summary
Android Purchase Flow
android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt
Read includeSuspended from Android options, log it in payloads, pass PurchaseOptions with includeSuspendedAndroid for full-type queries; extract productStatusAndroid and propagate into NitroProduct.
iOS Purchase Payload
ios/HybridRnIap.swift
Append introductoryOfferEligibility, promotionalOfferJWS (jws + offerId), and winBackOffer to iOS purchase payload when provided.
Core Types
src/types.ts
Add BillingResultAndroid, SubResponseCodeAndroid, ProductStatusAndroid, PromotionalOfferJwsInputIOS, WinBackOfferInputIOS; extend product/purchase/offer types and add includeSuspendedAndroid / iOS purchase fields.
Nitro Spec
src/specs/RnIap.nitro.ts
Add includeSuspended to NitroAvailablePurchasesAndroidOptions, add productStatusAndroid to NitroProduct, and add iOS purchase fields (introductoryOfferEligibility, promotionalOfferJWS, winBackOffer).
Type Bridge
src/utils/type-bridge.ts
Map productStatusAndroid from Nitro -> public Product in Android conversion path.
Public API surface / JS types
src/* (types, specs, utils)
Updated public interfaces and payload shapes to include the new Android/iOS fields (affects exported types and request shapes).
Docs — Release Notes
docs/blog/2026-01-19-release-14.8.0-billing-library-8.md
New release doc describing productStatusAndroid, suspended subscriptions, iOS win-back/promotional offers, JWS promos, intro-override, and sub-response codes.
Docs — Types & Guides
docs/static/llms.txt, docs/versioned_docs/**/guides/*, docs/docs/guides/troubleshooting.md
Add/describe isSuspendedAndroid, productStatusAndroid, iOS fields; change troubleshooting/lifecycle docs to use onPurchaseError/connected/initConnection patterns.
OpenIAP Versions
openiap-versions.json
Bumped OpenIAP package versions (apple → 1.3.12, google → 1.3.25, gql → 1.3.14, docs → 1.3.14).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

📱 iOS, 🤖 android, ❄️ types, dependencies, 💲 openiap

Poem

🐰 Hopped in with fields both new and bright,

Android statuses and suspended sight,
iOS offers, promo JWS in tow,
Types and docs aligned — off we go!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 clearly and concisely summarizes the main objective: syncing with OpenIAP v1.3.14 to bring Google Play Billing Library 8.0+ features and iOS WWDC 2025 enhancements, which aligns with the extensive changes across Android/iOS native code, TypeScript types, and documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @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 OpenIAP v1.3.14, significantly enhancing in-app purchase capabilities for both Android and iOS platforms. It introduces advanced features from Google Play Billing Library 8.0+ for Android, providing more detailed product status information and better handling of suspended subscriptions. For iOS, it incorporates new WWDC 2025 enhancements, enabling new types of promotional and win-back offers, and allowing developers to override introductory offer eligibility. These updates aim to provide developers with more control and insight into their in-app purchase flows.

Highlights

  • Android: Granular Product Status: The productStatusAndroid field is now available, providing detailed reasons why a product might not be fetched (e.g., 'ok', 'not-found', 'no-offers-available'). This enhances visibility into product availability.
  • Android: Suspended Subscriptions Handling: A new includeSuspended option for getAvailablePurchases allows retrieval of suspended subscriptions, which are identified by the isSuspendedAndroid field. This helps in managing user entitlements for subscriptions with payment issues.
  • Android: Enhanced Error Information: The SubResponseCodeAndroid provides more granular error details for billing operations, offering specific context for issues like 'payment-declined-due-to-insufficient-funds' or 'user-ineligible'.
  • iOS: WWDC 2025 Win-Back Offers: Support for winBackOffer has been added, enabling the implementation of win-back offers to re-engage churned subscribers on iOS 18+.
  • iOS: JWS Promotional Offers: New promotionalOfferJWS functionality introduces a simplified JWS format for promotional offers, back-deployed to iOS 15, streamlining the process of applying discounts.
  • iOS: Introductory Offer Eligibility Override: Developers can now override the system-determined introductory offer eligibility using introductoryOfferEligibility for iOS 15+.

🧠 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 Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@codecov

codecov Bot commented Jan 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.70%. Comparing base (9321405) to head (9d2a2d8).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3127      +/-   ##
==========================================
+ Coverage   65.68%   65.70%   +0.02%     
==========================================
  Files           9        9              
  Lines        1705     1706       +1     
  Branches      570      571       +1     
==========================================
+ Hits         1120     1121       +1     
  Misses        580      580              
  Partials        5        5              
Flag Coverage Δ
library 65.70% <100.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/utils/type-bridge.ts 77.06% <100.00%> (+0.08%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@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 is a significant update, syncing with OpenIAP v1.3.14 to incorporate new features from Google Play Billing Library 8.0+ and iOS enhancements. The changes are extensive, touching native Android and iOS code, TypeScript types, and documentation. My review focuses on ensuring the new features are correctly implemented. I've identified a potential issue in the Android implementation where an option might be ignored in a specific case. Overall, this is a great step forward in functionality.

Comment on lines 526 to 536
val result: List<OpenIapPurchase> = if (normalizedType != null) {
val typeEnum = parseProductQueryType(normalizedType)
RnIapLog.payload(
"getAvailablePurchases.native",
mapOf("type" to typeEnum.rawValue)
mapOf("type" to typeEnum.rawValue, "includeSuspended" to includeSuspended)
)
openIap.getAvailableItems(typeEnum)
} else {
RnIapLog.payload("getAvailablePurchases.native", mapOf("type" to "all"))
openIap.getAvailablePurchases(null)
RnIapLog.payload("getAvailablePurchases.native", mapOf("type" to "all", "includeSuspended" to includeSuspended))
openIap.getAvailablePurchases(purchaseOptions)
}

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.

high

The includeSuspended option will be ignored when a type is specified (e.g., 'subs' or 'inapp') because openIap.getAvailableItems(typeEnum) is called, which doesn't seem to accept the purchaseOptions that contain the includeSuspended flag. This will lead to inconsistent behavior where suspended purchases are only included when fetching all purchase types.

To fix this, you should use openIap.getAvailablePurchases(purchaseOptions) in both branches of the conditional and then filter the results by type if a type is provided. This ensures the includeSuspended option is always respected.

            val allPurchases = openIap.getAvailablePurchases(purchaseOptions)
            val result: List<OpenIapPurchase> = if (normalizedType != null) {
                val typeEnum = parseProductQueryType(normalizedType)
                RnIapLog.payload(
                    "getAvailablePurchases.native",
                    mapOf("type" to typeEnum.rawValue, "includeSuspended" to includeSuspended)
                )
                // Filter the purchases by type, as getAvailablePurchases fetches all types.
                allPurchases.filter { it.type.rawValue == normalizedType }
            } else {
                RnIapLog.payload("getAvailablePurchases.native", mapOf("type" to "all", "includeSuspended" to includeSuspended))
                allPurchases
            }

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in f986692.

Changes:

  • Now always uses openIap.getAvailablePurchases(purchaseOptions) to ensure includeSuspended is respected
  • Filters results by type after fetching when a type is specified

Thanks for catching this!

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Update: Reverted in 2984378.

After investigation, the suggested fix doesn't work due to OpenIAP API limitations:

  1. getAvailableItems(type) doesn't accept PurchaseOptions parameter
  2. Purchase objects don't have a type property for filtering

The includeSuspended option can only work when fetching all purchase types (without type filter). This is a limitation of the upstream OpenIAP library that would need to be addressed there.

Added a comment in the code to clarify this limitation.

@hyochan hyochan added 🎯 feature New feature 🚽 migration Activities due to changes in framework labels Jan 18, 2026
hyochan and others added 3 commits January 19, 2026 03:22
- Fix getAvailablePurchases to always use purchaseOptions with
  includeSuspended, then filter by type instead of using
  getAvailableItems which ignores the option
- Update docs to remove non-existent connectionError from useIAP
  examples and use correct API (connected state + onPurchaseError)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
OpenIAP's getAvailableItems doesn't accept PurchaseOptions parameter,
and Purchase objects don't have a type property for filtering.
The includeSuspended option only works when fetching all purchase types.

Added comment to clarify this API limitation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@hyochan hyochan merged commit 058901a into main Jan 18, 2026
11 checks passed
@hyochan hyochan deleted the feat/openiap-sync-1.3.14 branch January 18, 2026 19:01
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

🎯 feature New feature 🚽 migration Activities due to changes in framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant