3.1.0 - Full OpenIAP Ecosystem Adoption
· 4 min read
Expo IAP 3.1.0 graduates the project into the full OpenIAP ecosystem. The release ships with three dedicated native stacks:
- openiap-apple — StoreKit 2 implementation for Apple platforms
- openiap-google — Google Play Billing integration for Android
- openiap-gql — GraphQL helpers that drive types and tooling
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.
🚀 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 ofsubscriptionOfferDetailsAndroid
so Google Play discounts apply reliably.
🛡️ Safer Purchases & Better Errors
requestPurchase
on iOS explicitly rejects unsupported product types instead of silently treatingall
asin-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 genericid
is no longer repurposed for orders; when Google Play omits anorderId
(typical for consumables),transactionId
becomesnull
and clients should rely on the unifiedpurchaseToken
(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
orsubs
. Passingall
(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
, andrequestProducts
are removed. UsefetchProducts
with the unified purchase flow.
Minor Updates
- Removed the legacy
useIAP
state shims (currentPurchase
,currentPurchaseError
, and theirclear*
helpers) in favour of the hook’sonPurchaseSuccess
/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
- Recent work: Closed pull requests
- Release builds on the OpenIAP ecosystem: openiap.dev
Enjoy the smoother upgrade path and richer diagnostics shipped in 3.1.0! Let us know how it goes via GitHub issues.