3.4.4 - Android Input Type Field Naming Simplification
This release simplifies field naming in Android input types (RequestPurchaseAndroidProps and RequestSubscriptionAndroidProps). Since these types are already Android-specific, their fields no longer need the Android suffix.
Breaking Changes
Simplified Field Names in Android Input Types
Fields inside platform-specific input types no longer require the platform suffix. The parent type name already indicates the platform context.
Why this change?
When you write google: { offerToken: "..." }, the google key already tells you this is Android-specific. Adding Android suffix to fields inside is redundant:
// Redundant - we know it's Android from the parent
google: { offerTokenAndroid: "..." }
// Cleaner - parent context is sufficient
google: { offerToken: "..." }
Migration Guide
| Old Name (v3.4.3) | New Name (v3.4.4) |
|---|---|
offerTokenAndroid | offerToken |
isOfferPersonalizedAndroid | isOfferPersonalized |
obfuscatedAccountIdAndroid | obfuscatedAccountId |
obfuscatedProfileIdAndroid | obfuscatedProfileId |
purchaseTokenAndroid | purchaseToken |
replacementModeAndroid | replacementMode |
developerBillingOptionAndroid | developerBillingOption |
Before (v3.4.3):
await requestPurchase({
request: {
google: {
skus: ['product_id'],
offerTokenAndroid: discountOffer.offerTokenAndroid,
isOfferPersonalizedAndroid: true,
obfuscatedAccountIdAndroid: 'user_123',
},
},
type: 'in-app',
});
After (v3.4.4):
await requestPurchase({
request: {
google: {
skus: ['product_id'],
offerToken: discountOffer.offerTokenAndroid, // Note: response field keeps suffix
isOfferPersonalized: true,
obfuscatedAccountId: 'user_123',
},
},
type: 'in-app',
});
Important: Response Types Keep Suffixes
The suffix removal only applies to input types (request parameters). Response types still use suffixes because they're cross-platform:
// Response fields KEEP the Android suffix
const product = products[0] as ProductAndroid;
const discountOffer = product.discountOffers?.[0];
// These response fields still have Android suffix
console.log(discountOffer?.offerTokenAndroid); // ✓ Keep suffix
console.log(discountOffer?.percentageDiscountAndroid); // ✓ Keep suffix
// But input fields don't need it anymore
await requestPurchase({
request: {
google: {
skus: [product.id],
offerToken: discountOffer?.offerTokenAndroid, // Input: no suffix
},
},
type: 'in-app',
});
One-Time Purchase Discount Offers (Android 7.0+)
This release also adds support for discount offers on one-time (in-app) purchases:
import {fetchProducts, requestPurchase} from 'expo-iap';
import type {ProductAndroid} from 'expo-iap';
// 1. Fetch products with discount offers
const products = await fetchProducts({
skus: ['premium_upgrade'],
type: 'in-app',
});
const product = products[0] as ProductAndroid;
// 2. Get the discount offer
const discountOffer = product.discountOffers?.[0];
// 3. Purchase with the discount
if (discountOffer?.offerTokenAndroid) {
await requestPurchase({
request: {
google: {
skus: [product.id],
offerToken: discountOffer.offerTokenAndroid, // Use simplified input field
},
},
type: 'in-app',
});
}
Naming Convention Summary
| Field Location | Suffix Required? | Example |
|---|---|---|
Inside RequestPurchaseAndroidProps | NO | offerToken |
Inside RequestSubscriptionAndroidProps | NO | purchaseToken |
| Cross-platform response type | YES | DiscountOffer.offerTokenAndroid |
Closes
- #307 - Support offerToken for in-app products (one-time purchases)
OpenIAP Versions
| Package | Version |
|---|---|
| openiap-gql | 1.3.15 |
| openiap-google | 1.3.26 |
| openiap-apple | 1.3.13 |
For detailed changes, see the OpenIAP Release Notes.
