Skip to main content

3.0.0 — OpenIAP Integration, Unified Core, Leaner API

· 5 min read
Hyo
Expo IAP Maintainer

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 old jwsRepresentationIOS 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 (use purchaseToken on all platforms). On iOS, purchaseToken contains the JWS representation previously accessed via receipts.
    • Removed jwsRepresentationIOS in favor of the unified purchaseToken.
  • Removed functions

    • getProducts, getSubscriptions, requestProducts, requestSubscription
    • getPurchaseHistory / getPurchaseHistories
    • Non‑suffixed iOS aliases (use *IOS variants)
  • Changed behavior

    • showManageSubscriptionsIOS(): Promise<Purchase[]> — now returns purchases instead of boolean.
    • getAvailablePurchases options: only accepts alsoPublishToEventListenerIOS and onlyIncludeActiveItemsIOS.

📋 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 and pod 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 boolean willAutoRenew.
  • 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

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