3.0.0 — OpenIAP Integration, Unified Core, Leaner API
Expo IAP 3.0.0 is a major release that fully integrates OpenIAP’s Android and iOS modules. Expo IAP is no longer just a framework bridge — it now leverages a centralized OpenIAP core for shared logic across platforms and SDKs. The result is a leaner, more maintainable codebase with faster iteration and greater stability.
🚀 Highlights
- Unified tokens:
Purchase.purchaseToken
is now the single source on both platforms (iOS JWS or Android token). The oldjwsRepresentationIOS
is removed. - Leaner API: Legacy helpers are removed. Use
fetchProducts
,requestPurchase
,getAvailablePurchases
, and listeners. - iOS parity: Only
*IOS
helpers remain for iOS‑specific behavior.showManageSubscriptionsIOS()
now returns an array of purchases instead of a boolean. - Stronger types: Consolidated product/purchase types; removed legacy aliases and fields for clarity.
- OpenIAP everywhere: Android uses openiap-google and iOS uses openiap-apple. Shared, centralized logic simplifies maintenance and keeps frameworks in sync.
🔍 Key Changes
✅ Full Integration Across Client Platforms (Android · iOS) Platform‑specific IAP logic has been unified into OpenIAP modules, minimizing fragmentation across ecosystems.
✅ Lean Codebase (~75% reduction) Overall code size has been significantly reduced, lowering complexity and maintenance costs.
✅ Centralized Core Architecture Common logic lives in the core library, enabling consistent behavior and faster feature expansion across frameworks.
✅ Improved Stability & Maintainability Bug fixes and features land once in the core, eliminating duplication and improving reliability.
💥 Breaking Changes
-
Removed fields
- Removed
transactionReceipt
(usepurchaseToken
on all platforms). On iOS,purchaseToken
contains the JWS representation previously accessed via receipts. - Removed
jwsRepresentationIOS
in favor of the unifiedpurchaseToken
.
- Removed
-
Removed functions
getProducts
,getSubscriptions
,requestProducts
,requestSubscription
getPurchaseHistory
/getPurchaseHistories
- Non‑suffixed iOS aliases (use
*IOS
variants)
-
Changed behavior
showManageSubscriptionsIOS(): Promise<Purchase[]>
— now returns purchases instead ofboolean
.getAvailablePurchases
options: only acceptsalsoPublishToEventListenerIOS
andonlyIncludeActiveItemsIOS
.
📋 Recent Patch Releases (v2.9.x)
Before the major 3.0.0 release, several patch versions improved stability and fixed issues:
v2.9.7 — Android/iOS improvements and subscription offer tokens
- Android: Removed ensureConnection wrapper, added pre-checks, and dropped deprecated product fields (use
nameAndroid
,oneTimePurchaseOfferDetailsAndroid
,subscriptionOfferDetailsAndroid
). - iOS: Added ensureConnection() guard across public APIs; fixed main-actor state mutation and minor warnings.
- Heads-up for Android subscriptions: When purchasing subscriptions, pass selected offer tokens via
subscriptionOffers
to build BillingFlowParams correctly. Example provided in the original release notes.
v2.9.6 — Metro bundling fix
- Fixed Metro bundling issue that could crash apps when using
useIAP()
under certain project setups. - Replaced ambiguous import '.' with explicit import './index' in the hook implementation.
- No runtime behavior changes — strictly fixes bundling resolution.
v2.9.5 — Pin openiap and deprecate 2.9.0–2.9.4
- iOS: Podspec now pins openiap to 1.1.9 to avoid version drift during pod install.
- Deprecated 2.9.0–2.9.4. Please upgrade to 2.9.5.
- Upgrade notes: Run
npx expo prebuild -p ios
andpod install
after updating.
v2.9.3 — iOS error fixes and CocoaPods hardening
- iOS: Replaced thrown OpenIapError.* usages and nonexistent event types with proper OpenIapFailure cases.
- iOS: Relied on type inference for error event listener to avoid missing type symbols.
- Plugin(iOS): Ensured Podfile includes GitHub Specs before CDN and added stability envs to reduce CDN HTTP/2 flakiness.
- Plugin(iOS): Applied the same improvements when injecting a local openiap pod for development.
v2.9.1 — iOS fixes and error improvements
- iOS:
getPromotedProductIOS
now returns a full serialized Product;subscriptionStatusIOS
returns{ state, renewalInfo? }
with a real booleanwillAutoRenew
. - Errors: Expanded codes + friendlier messages; support object-style
new PurchaseError({ ... })
(positional args still work). - Docs: Docusaurus supports GitHub Pages via dynamic baseUrl; added conventions for PurchaseError construction.
- Example iOS: Pinned openiap to 1.1.7 from git to avoid trunk lag.
Quick Migration
Fetch products (in‑app or subs)
import {fetchProducts, type ProductSubscription} from 'expo-iap';
const inapps = await fetchProducts({skus: ['prod1', 'prod2'], type: 'in-app'});
const subs = (await fetchProducts({
skus: ['sub_monthly'],
type: 'subs',
})) as ProductSubscription[];
Request purchase (products or subs)
import {requestPurchase} from 'expo-iap';
// In‑app
await requestPurchase({
request: {ios: {sku: 'prod1'}, android: {skus: ['prod1']}},
type: 'in-app',
});
// Subscriptions (Android supply offer tokens)
await requestPurchase({
request: {
ios: {sku: 'sub_monthly'},
android: {
skus: ['sub_monthly'],
subscriptionOffers: [
{sku: 'sub_monthly', offerToken: 'your-offer-token'},
],
},
},
type: 'subs',
});
Restore/available purchases
import {getAvailablePurchases, restorePurchases} from 'expo-iap';
// iOS‑specific flags only
const purchases = await getAvailablePurchases({
alsoPublishToEventListenerIOS: false,
onlyIncludeActiveItemsIOS: true,
});
// Cross‑platform helper that syncs on iOS then lists
const restored = await restorePurchases({
alsoPublishToEventListenerIOS: false,
onlyIncludeActiveItemsIOS: true,
});
Tokens and finishing transactions
import {finishTransaction, type Purchase} from 'expo-iap';
function getToken(p: Purchase) {
return p.purchaseToken; // iOS: JWS, Android: purchaseToken
}
await finishTransaction({purchase: somePurchase, isConsumable: true});
Notes
- iOS promoted products listener remains
promotedProductListenerIOS
. getStorefront()
is now the unified storefront helper across platforms.
Changelog
See CHANGELOG.md
for the full list of changes in 3.0.0.
🔗 Repositories to Explore
- openiap-apple (iOS)
- openiap-google (Android)
The OpenIAP core library is where the shared logic and architecture live — the foundation for review, extensibility, and cross‑SDK consistency.
🌟 Why This Matters
- Standardizes the IAP experience across frameworks, improving trust for both developers and users
- Speeds up responses to platform‑specific issues (fix once at the core)
- Reduces risk and shortens release cycles via a smaller codebase and broader test coverage
Follow for faster updates: @hyodotdev