Skip to main content

2.8.0 Migration Guide - iOS Field Naming Convention Update

· 6 min read
Hyo
Expo IAP Maintainer

Breaking Changes

Version 2.8.0 introduces naming convention changes:

  1. iOS suffix convention: Fields with iOS suffixes now use uppercase IOS instead of Ios
  2. ID suffix convention: All fields ending with ID now use Id instead for consistency (e.g., subscriptionGroupIDsubscriptionGroupId, bundleIDbundleId)

Note: Android field names remain unchanged as they already follow the correct convention (e.g., autoRenewingAndroid, purchaseTokenAndroid).

What Changed

iOS Changes

Product Types

ProductIOS & ProductSubscriptionIOS:

  • displayName - Product display name
  • isFamilyShareable - Family sharing availability
  • jsonRepresentation - JSON representation of product
  • introductoryPriceNumberOfPeriodsIOS - Introductory price period count
  • introductoryPriceSubscriptionPeriodIOS - Introductory price period
  • introductoryPriceAsAmountIOS - Introductory price amount
  • introductoryPricePaymentModeIOS - Introductory price payment mode
  • subscriptionPeriodNumberIOS - Subscription period number
  • subscriptionPeriodUnitIOS - Subscription period unit

SubscriptionInfo:

  • subscriptionGroupId - Subscription group identifier (changed from subscriptionGroupID)

Purchase Types

ProductPurchaseIOS includes these StoreKit 2 fields:

  • quantityIOS, originalTransactionDateIOS, originalTransactionIdentifierIOS
  • expirationDateIOS, webOrderLineItemIdIOS, environmentIOS
  • storefrontCountryCodeIOS, appBundleIdIOS, productTypeIOS
  • subscriptionGroupIdIOS, isUpgradedIOS, ownershipTypeIOS
  • reasonIOS, reasonStringRepresentationIOS, transactionReasonIOS
  • revocationDateIOS, revocationReasonIOS, offerIOS
  • priceIOS, currencyIOS, jwsRepresentationIOS (deprecated)

AppTransactionIOS (iOS 16.0+):

  • appTransactionId - App transaction identifier (changed from appTransactionID)
  • bundleId - Bundle identifier (changed from bundleID)
  • appId - App identifier (changed from appID)
  • appVersionId - App version identifier (changed from appVersionID)

Breaking Changes - Field Renaming:

iOS Suffix Changes (Ios → IOS)

Old Field NameNew Field Name
quantityIosquantityIOS
originalTransactionDateIosoriginalTransactionDateIOS
originalTransactionIdentifierIosoriginalTransactionIdentifierIOS
appBundleIdIosappBundleIdIOS
productTypeIosproductTypeIOS
subscriptionGroupIdIossubscriptionGroupIdIOS
webOrderLineItemIdIoswebOrderLineItemIdIOS
expirationDateIosexpirationDateIOS
isUpgradedIosisUpgradedIOS
ownershipTypeIosownershipTypeIOS
revocationDateIosrevocationDateIOS
revocationReasonIosrevocationReasonIOS
transactionReasonIostransactionReasonIOS
environmentIosenvironmentIOS
storefrontCountryCodeIosstorefrontCountryCodeIOS
reasonIosreasonIOS
offerIosofferIOS
priceIospriceIOS
currencyIoscurrencyIOS
jwsRepresentationIosjwsRepresentationIOS
reasonStringRepresentationIosreasonStringRepresentationIOS

ID Suffix Changes (ID → Id)

Old Field NameNew Field NameType/Context
subscriptionGroupIDsubscriptionGroupIdSubscriptionInfo
appTransactionIDappTransactionIdAppTransactionIOS
bundleIDbundleIdAppTransactionIOS
appIDappIdAppTransactionIOS
appVersionIDappVersionIdAppTransactionIOS

Function Parameter Changes

FunctionOld ParameterNew Parameter
isEligibleForIntroOfferIOSgroupIDgroupId

Android Changes

Product Types

ProductAndroid & ProductSubscriptionAndroid:

  • name - Product display name
  • oneTimePurchaseOfferDetails - One-time purchase offer details
  • subscriptionOfferDetails - Subscription offer details array

Purchase Types

ProductPurchaseAndroid includes these Android Billing Library fields:

  • ids - Array of product IDs
  • purchaseTokenAndroid - Android purchase token (deprecated, use purchaseToken)
  • dataAndroid - Purchase data
  • signatureAndroid - Purchase signature
  • autoRenewingAndroid - Auto-renewal status
  • purchaseStateAndroid - Purchase state enum
  • isAcknowledgedAndroid - Acknowledgment status
  • packageNameAndroid - App package name
  • developerPayloadAndroid - Developer payload
  • obfuscatedAccountIdAndroid - Obfuscated account ID
  • obfuscatedProfileIdAndroid - Obfuscated profile ID

Request Props

RequestPurchaseAndroidProps:

  • isOfferPersonalized - For Android Billing V5 personalized pricing

No Breaking Changes - All Android fields maintain existing naming convention.

How to Migrate

Step 1: Update Field References

Search your codebase for any references to the old field names and update them:

// Before (2.7.x)
const purchase = await requestPurchase({sku: 'product-id'});
if (purchase.expirationDateIos) {
console.log('Expires:', purchase.expirationDateIos);
}

// After (2.8.0)
// Note: requestPurchase API signature has also changed in 2.8.0
const purchase = await requestPurchase({
request: {
ios: {sku: 'product-id'},
android: {skus: ['product-id']},
},
type: 'in-app',
});
if (purchase.expirationDateIOS) {
console.log('Expires:', purchase.expirationDateIOS);
}

Bug Fixes and Operational Notes

  • iOS Hot Reload Fix (2.7.7): This version addresses critical failures during React Native's fast refresh on iOS, which could leave StoreKit in an inconsistent state. Previously, concurrent operations like Promise.all([fetchProducts(...), getAvailablePurchases()]) would fail during hot reloads. The native module now cleans up its state during initConnection(), validates connections with ensureConnection() across all public APIs (similar to Android), and properly manages StoreKit resources. No code changes are needed to benefit from this fix, but expo-iap@2.7.7+ is required.
  • Metro bundling resolution (2.9.6): Fixed an ambiguous import in the hook implementation that could cause Metro to attempt to resolve ../../.. and crash. The import now explicitly targets ./index.

v2.7.3 Release — Google Play Billing Library v8.0.0 Support

We shipped v2.7.3 to add full support for Google Play Billing Library v8.0.0. This ensures compatibility with the latest Android billing features and improves error diagnostics.

What's New

  • Upgraded Google Play Billing from v7.0.0 to v8.0.0
  • Enhanced error handling with sub-response codes for better debugging
  • API compatibility updates for new callback signatures

Key Changes

  • Updated queryProductDetailsAsync callback to use QueryProductDetailsResult
  • Improved enablePendingPurchases configuration
  • Removed deprecated, hardcoded Kotlin version constraints

Breaking Changes

Android Kotlin version requirement: Play Billing v8.0.0 requires Kotlin 2.0+. Because expo-modules-core did not yet support Kotlin v2 at the time, you must set Kotlin 2.0.21 explicitly via expo-build-properties:

{
"expo": {
"plugins": [
[
"expo-build-properties",
{
"android": {
"kotlinVersion": "2.0.21"
}
}
]
]
}
}

Installation

If you're upgrading to v2.7.3:

npx expo install expo-iap@2.7.3

Don't forget to add the expo-build-properties configuration to your app.json if you haven't already.

Step 2: Update Type Imports and Declarations

Type names have also been updated to use uppercase IOS:

// Before (2.7.x)
import {
ProductIOS,
ProductPurchaseIos,
ProductSubscriptionIOS,
ProductStatusIos,
} from 'expo-iap';

// After (2.8.0)
import {
ProductIOS,
ProductPurchaseIOS,
ProductSubscriptionIOS,
ProductStatusIOS,
} from 'expo-iap';

Note: The old type names are still available as deprecated aliases for backward compatibility, but we recommend updating to the new names.

Step 3: Update Type Checks

If you're using TypeScript and checking for iOS-specific fields:

// Before (2.7.x)
if ('expirationDateIos' in purchase) {
// Handle subscription
}

// After (2.8.0)
if ('expirationDateIOS' in purchase) {
// Handle subscription
}

Step 4: Update ID Field References

Update all ID field references to use Id instead:

// Before (2.7.x)
const appTransaction = await getAppTransactionIOS();
console.log(appTransaction.bundleID);
console.log(appTransaction.appID);

// After (2.8.0)
const appTransaction = await getAppTransactionIOS();
console.log(appTransaction.bundleId);
console.log(appTransaction.appId);

Step 5: Update Subscription Helpers

If you're using the subscription helper functions:

// Before (2.7.x)
const subscription = {
expirationDateIos: purchase.expirationDateIos,
environmentIos: purchase.environmentIos,
};

// After (2.8.0)
const subscription = {
expirationDateIOS: purchase.expirationDateIOS,
environmentIOS: purchase.environmentIOS,
};

Quick Migration Script

You can use this regex find/replace pattern in your IDE to quickly update most occurrences:

Find Pattern (Regex):

\b(\w+)(Ios)\b

Replace Pattern:

$1IOS

⚠️ Note: Review each replacement carefully as this might affect non-field references.

Why This Change?

These changes align with widely-adopted naming conventions:

  1. iOS suffix: Acronyms at the end of identifiers are written in uppercase (e.g., dataIOS, configIOS)
  2. ID suffix: The Id convention is more common in modern JavaScript/TypeScript codebases (e.g., userId, productId, transactionId)

This makes the codebase more consistent and follows best practices in the TypeScript/JavaScript ecosystem.

Need Help?

If you encounter any issues during migration: