Skip to main content

3.1.0 - Full OpenIAP Ecosystem Adoption

· 4 min read
Hyo
Expo IAP Maintainer

Expo IAP 3.1.0 graduates the project into the full OpenIAP ecosystem. The release ships with three dedicated native stacks:

From 3.1.0 onward, Expo IAP stays in lockstep with these modules: Apple v1.2.2, Google v1.2.6, and GQL v1.0.8. That shared version alignment gives Expo IAP stable native compatibility and a unified type system straight from the OpenIAP schema.

👉 View the 3.1.0 release

🚀 Highlights

  • Adopted the full OpenIAP core stack—openiap-gql, openiap-apple v1.2.2, and openiap-google v1.2.6)—bringing Expo IAP into alignment with the shared ecosystem used across Flutter, React Native, and KMP.
  • Trimmed roughly two thirds of our custom native bridge code by delegating logic to the OpenIAP modules.
  • Expanded automated coverage to about 98%, spanning purchase flows, native bridge entry points, and error mapping utilities.

🔁 OpenIAP Upgrades

  • Normalized purchase payloads on both platforms so every bridge call sanitizes platform casing and forwards the complete OpenIAP record.
  • Migrated Android to the new RequestPurchaseProps / PurchaseResult / ErrorCode contracts, achieving parity with the Apple module.
  • Centralized native dependency versions via openiap-versions.json; Gradle now fails fast if the Google artifact version is missing and scripts/migrations read from one source of truth.

🐞 Bug Fixes

  • fix(android): honor subscription offerToken (#214) restores proper handling of subscriptionOfferDetailsAndroid so Google Play discounts apply reliably.

🛡️ Safer Purchases & Better Errors

  • requestPurchase on iOS explicitly rejects unsupported product types instead of silently treating all as in-app.
  • Error handling now consistently routes through the shared ErrorCode table so promise rejections, platform conversions, and predicates remain aligned.
  • Additional coverage for createPurchaseError, ErrorCodeUtils, and the user-friendly error helper keeps error copy in sync with OpenIAP terminology.

🛠️ Tooling & Workflow

  • Contributor docs clarify how to bump OpenIAP packages, regenerate types, and keep openiap-versions.json synchronized for Android and iOS builds.

⚠️ Important Changes

  • Transaction identifiers: transactionId is reinstated as the primary store reference (orderId on Android, StoreKit transaction ID on iOS). Android’s generic id is no longer repurposed for orders; when Google Play omits an orderId (typical for consumables), transactionId becomes null and clients should rely on the unified purchaseToken (Android purchase token / iOS JWS). This value is the canonical receipt for server validation. See the related react-native-iap discussion.
  • iOS request types: purchase requests must specify either in-app or subs. Passing all (or any other type) throws an explicit error.
  • Promoted products: events now emit the full sanitized product payload; downstream listeners should expect the entire object instead of just productId.
  • Deprecated helpers removed: getProducts, requestSubscription, and requestProducts are removed. Use fetchProducts with the unified purchase flow.

Minor Updates

  • Removed the legacy useIAP state shims (currentPurchase, currentPurchaseError, and their clear* helpers) in favour of the hook’s onPurchaseSuccess / onPurchaseError callbacks (#213).

📦 Installation

bun add expo-iap@3.1.0
# or
npm install expo-iap@3.1.0
# or
yarn add expo-iap@3.1.0

🔗 References

Enjoy the smoother upgrade path and richer diagnostics shipped in 3.1.0! Let us know how it goes via GitHub issues.