Skip to main content

2.6.0 - Major iOS Improvements

ยท 4 min read
Hyo
Expo IAP Maintainer

We're excited to announce the release of expo-iap v2.6.0! This release brings significant improvements to iOS functionality, better TypeScript support, and enhanced developer experience.

๐ŸŽ‰ What's Newโ€‹

1. Proper iOS Subscription Data Serializationโ€‹

The biggest improvement in this release is the proper serialization of iOS subscription data. Previously, the subscription field would return undefined for subscription products. Now, all subscription information is properly serialized and accessible.

Before (v2.5.x)โ€‹

const subscriptions = await getSubscriptions(['com.example.premium']);
console.log(subscriptions[0].subscription); // undefined ๐Ÿ˜ข

After (v2.6.0)โ€‹

const subscriptions = await getSubscriptions(['com.example.premium']);
console.log(subscriptions[0].subscription); // โœ… Full subscription data!

2. Improved Type Structureโ€‹

We've restructured how period information is returned to be more consistent and useful. The period and subscriptionPeriod properties now return objects with unit and value properties instead of just the unit string.

Before (v2.5.x):

type SubscriptionInfo = {
subscriptionPeriod: SubscriptionIosPeriod; // 'DAY' | 'WEEK' | 'MONTH' | 'YEAR'
};

After (v2.6.0):

type SubscriptionInfo = {
subscriptionPeriod: {
unit: SubscriptionIosPeriod; // 'DAY' | 'WEEK' | 'MONTH' | 'YEAR'
value: number; // e.g., 1, 3, 6, 12
};
};

This change provides more detailed information about subscription periods. For example, instead of just knowing a subscription is "MONTH", you now know if it's "1 MONTH", "3 MONTHS", etc.

3. New getStorefront() APIโ€‹

Get the user's App Store country code:

import {getStorefront} from 'expo-iap';

const countryCode = await getStorefront();
console.log('User storefront:', countryCode); // 'US', 'GB', 'JP', etc.

4. AppTransaction Support (iOS 16.0+)โ€‹

For premium apps or apps that were previously paid, you can now verify the initial app purchase:

import {getAppTransaction} from 'expo-iap';

const appTransaction = await getAppTransaction();
if (appTransaction) {
console.log('App Transaction ID:', appTransaction.appTransactionID);
console.log('Purchase Date:', new Date(appTransaction.originalPurchaseDate));
// Send deviceVerification to your server for validation
}

5. Comprehensive iOS Subscription Offers Documentationโ€‹

We've added extensive documentation for handling iOS subscription offers:

  • Understanding introductory and promotional offers
  • Checking user eligibility
  • Implementing offer UI
  • Best practices and troubleshooting

Check out the new iOS Subscription Offers Guide.

โš ๏ธ Breaking Changesโ€‹

1. Period Structure Changesโ€‹

The period and subscriptionPeriod properties now return objects with unit and value properties:

// Before
if (offer.period === 'MONTH') {
console.log('Monthly offer');
}

// After
if (offer.period.unit === 'MONTH') {
console.log(`${offer.period.value} month(s) offer`);
}

2. Optional Subscription Fieldโ€‹

The subscription field in ProductIOS is now optional to reflect that not all iOS products have subscription information:

// Before
type ProductIOS = {
subscription: SubscriptionInfo; // Always required
};

// After
type ProductIOS = {
subscription?: SubscriptionInfo; // Optional - only present for subscriptions
};

Migration: Update your code to handle the optional subscription field:

// Check if product is a subscription
if (product.subscription) {
// Handle subscription-specific logic
console.log('Period:', product.subscription.subscriptionPeriod);
}

3. Method Naming Updateโ€‹

To improve consistency, we've updated the purchase history method naming:

  • Deprecated: getPurchaseHistory() (singular)
  • New: getPurchaseHistories() (plural)

The useIAP hook already uses the plural form:

const {purchaseHistories, getPurchaseHistories} = useIAP();

๐Ÿ“‹ Complete Exampleโ€‹

Here's a complete example showing how to work with the new types:

import {useIAP} from 'expo-iap';

function ProductList() {
const {products} = useIAP();

return (
<View>
{products.map((product) => (
<View key={product.productId}>
<Text>{product.displayName}</Text>
<Text>{product.localizedPrice}</Text>

{product.subscription && (
<View>
<Text>
Subscription Period:{' '}
{product.subscription.subscriptionPeriod.value}{' '}
{product.subscription.subscriptionPeriod.unit.toLowerCase()}(s)
</Text>

{product.subscription.introductoryOffer && (
<Text>
Intro Offer:{' '}
{product.subscription.introductoryOffer.displayPrice} for{' '}
{product.subscription.introductoryOffer.period.value}{' '}
{product.subscription.introductoryOffer.period.unit.toLowerCase()}
(s)
</Text>
)}
</View>
)}
</View>
))}
</View>
);
}

๐Ÿ› Bug Fixesโ€‹

  • Fixed iOS subscription data not being properly serialized
  • Fixed period information returning raw values instead of structured data
  • Improved error handling for platform-specific methods
  • Fixed inconsistent naming between getPurchaseHistory and purchaseHistories

๐Ÿ“š Documentation Updatesโ€‹

  • Added iOS Subscription Offers guide
  • Updated type definitions documentation
  • Added examples for new APIs
  • Improved troubleshooting section
  • Updated migration guide for naming consistency

๐Ÿ’ช Benefitsโ€‹

These improvements provide several benefits:

  1. Better Type Safety: The TypeScript compiler can now catch more potential errors at compile time
  2. More Accurate Data: Period information now includes both unit and value, providing complete subscription duration details
  3. Clearer Intent: Optional types make it explicit which products are subscriptions
  4. Consistent API: Naming conventions are now consistent throughout the library
  5. Future-Proof: These changes align better with Apple's StoreKit 2 data structures

๐Ÿ™ Acknowledgmentsโ€‹

Special thanks to:

  • @Navipro70 for identifying the subscription serialization issue and providing valuable feedback
  • @matthieuMay for the initial iOS type improvements
  • All contributors who helped test and improve this release

๐Ÿ“ฆ Installationโ€‹

Update to the latest version:

npm install expo-iap@2.6.0
# or
yarn add expo-iap@2.6.0

What's Next?โ€‹

We're working on:

  • Android subscription offers improvements
  • Better error messages and debugging tools
  • Performance optimizations
  • More comprehensive examples

Stay tuned for more updates! If you have any feedback or suggestions, please open an issue.

Happy coding! ๐Ÿš€