Skip to content
This repository was archived by the owner on Apr 26, 2026. It is now read-only.

Commit ba335f3

Browse files
authored
feat: update openiap and support advancedCommerceDataIOS (#3112)
- Add advancedCommerceDataIOS support for StoreKit 2 attribution tracking - Support google/apple fields with android/ios fallback (deprecated) - Deprecate requestPurchaseOnPromotedProductIOS - Update documentation with new field names - Add tests for new features - Update OpenIAP to `apple 1.3.6`, `google 1.3.15`, `gql 1.3.6` Closes #3106 Co-authored-by: hlus <kyshbogdan@gmail.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added iOS advancedCommerceData support and new Android billing-program & external-link purchase helpers; promoted-product flow now returns a boolean and supports a StoreKit 2 recommended listener + requestPurchase path. * Examples now include type: 'in-app' in purchase calls. * **Documentation** * Updated examples and guides to use apple/google keys (ios/android deprecated), subscriptionOffers guidance, and promoted-product deprecation notes. * **Tests** * Added tests for apple/google precedence and iOS advancedCommerceData propagation. * **Chores** * Bumped platform/docs version metadata. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 9a58425 commit ba335f3

15 files changed

Lines changed: 478 additions & 94 deletions
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
---
2+
slug: release-14.6.3
3+
title: Release 14.6.3 - Advanced Commerce Data & Platform Field Updates
4+
authors: [hyochan]
5+
tags: [release, ios, android, storekit2, attribution]
6+
description: React Native IAP 14.6.3 adds advancedCommerceData support for iOS attribution tracking and introduces the new google/apple platform fields with deprecation of ios/android fields.
7+
date: 2025-12-24
8+
---
9+
10+
# React Native IAP 14.6.3
11+
12+
14.6.3 brings **advancedCommerceData** support for iOS attribution tracking using StoreKit 2's `Product.PurchaseOption.custom`, along with updated platform field naming conventions and improved type safety for Billing Programs API.
13+
14+
<!-- truncate -->
15+
16+
## What's New
17+
18+
### Advanced Commerce Data for iOS
19+
20+
This release adds support for `advancedCommerceData` in iOS purchase requests, enabling attribution tracking through StoreKit 2's custom purchase options.
21+
22+
```typescript
23+
import {requestPurchase} from 'react-native-iap';
24+
25+
await requestPurchase({
26+
request: {
27+
apple: {
28+
sku: 'com.example.premium',
29+
advancedCommerceData: 'your-attribution-token-here',
30+
},
31+
},
32+
type: 'in-app',
33+
});
34+
```
35+
36+
This feature allows you to pass attribution data to Apple for analytics and marketing attribution purposes. The data is passed through StoreKit 2's `Product.PurchaseOption.custom` API.
37+
38+
### New Platform Field Naming: `apple` and `google`
39+
40+
We've introduced new, clearer platform field names for purchase requests:
41+
42+
- `apple` (replaces `ios`)
43+
- `google` (replaces `android`)
44+
45+
**Before (deprecated):**
46+
47+
```typescript
48+
await requestPurchase({
49+
request: {
50+
ios: {sku: 'premium_monthly'},
51+
android: {skus: ['premium_monthly']},
52+
},
53+
type: 'in-app',
54+
});
55+
```
56+
57+
**After (recommended):**
58+
59+
```typescript
60+
await requestPurchase({
61+
request: {
62+
apple: {sku: 'premium_monthly'},
63+
google: {skus: ['premium_monthly']},
64+
},
65+
type: 'in-app',
66+
});
67+
```
68+
69+
The old `ios` and `android` fields are still supported for backward compatibility but are now deprecated. We recommend migrating to the new field names.
70+
71+
### Deprecated: `requestPurchaseOnPromotedProductIOS`
72+
73+
The `requestPurchaseOnPromotedProductIOS()` function is now deprecated. In StoreKit 2, promoted products can be purchased directly via the standard `requestPurchase()` flow.
74+
75+
**Before (deprecated):**
76+
77+
```typescript
78+
// Old approach
79+
await requestPurchaseOnPromotedProductIOS();
80+
```
81+
82+
**After (recommended):**
83+
84+
```typescript
85+
import {promotedProductListenerIOS, requestPurchase} from 'react-native-iap';
86+
87+
// Listen for promoted product taps
88+
promotedProductListenerIOS(async (product) => {
89+
await requestPurchase({
90+
request: {apple: {sku: product.id}},
91+
type: 'in-app',
92+
});
93+
});
94+
```
95+
96+
This approach gives you more control over the purchase flow and integrates better with your existing error handling and UI logic.
97+
98+
### Improved Type Safety for Billing Programs API
99+
100+
The Billing Programs API functions now use `MutationField` types for better type inference:
101+
102+
```typescript
103+
// These functions now have improved type safety
104+
isBillingProgramAvailableAndroid('external-offer');
105+
createBillingProgramReportingDetailsAndroid('external-offer');
106+
launchExternalLinkAndroid({...});
107+
```
108+
109+
## OpenIAP Updates
110+
111+
- **openiap-apple**: [1.3.2 → 1.3.7](https://github.com/hyodotdev/openiap/compare/apple-v1.3.2...apple-v1.3.7)
112+
- **openiap-google**: [1.3.14 → 1.3.16](https://github.com/hyodotdev/openiap/compare/google-v1.3.14...google-v1.3.16)
113+
- **openiap-gql**: [1.3.4 → 1.3.8](https://github.com/hyodotdev/openiap/compare/1.3.4...1.3.8)
114+
115+
## Migration Guide
116+
117+
### Platform Fields
118+
119+
Update your purchase requests to use the new field names:
120+
121+
```diff
122+
await requestPurchase({
123+
request: {
124+
- ios: {sku: 'product_id'},
125+
- android: {skus: ['product_id']},
126+
+ apple: {sku: 'product_id'},
127+
+ google: {skus: ['product_id']},
128+
},
129+
type: 'in-app',
130+
});
131+
```
132+
133+
### Promoted Products (iOS)
134+
135+
Replace `requestPurchaseOnPromotedProductIOS()` with the listener pattern:
136+
137+
```diff
138+
- await requestPurchaseOnPromotedProductIOS();
139+
140+
+ promotedProductListenerIOS(async (product) => {
141+
+ await requestPurchase({
142+
+ request: {apple: {sku: product.id}},
143+
+ type: 'in-app',
144+
+ });
145+
+ });
146+
```
147+
148+
## Installation
149+
150+
```bash
151+
npm install react-native-iap react-native-nitro-modules
152+
# or
153+
yarn add react-native-iap react-native-nitro-modules
154+
# or
155+
bun add react-native-iap react-native-nitro-modules
156+
```
157+
158+
Check out the [documentation](/docs/intro) for details on all features.
159+
160+
Questions or feedback? Reach out via [GitHub issues](https://github.com/hyochan/react-native-iap/issues).

docs/docs/api/methods/core-methods.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -751,16 +751,29 @@ Returns: `Promise<Product | null>`
751751

752752
### requestPurchaseOnPromotedProductIOS()
753753

754+
> **Deprecated**: In StoreKit 2, promoted products can be purchased directly via the standard `requestPurchase()` flow. Use `promotedProductListenerIOS` to receive the product ID when a user taps a promoted product, then call `requestPurchase()` with the received SKU directly.
755+
754756
Initiates the purchase flow for the currently promoted product. Requires iOS 11+.
755757

756758
```ts
759+
// Recommended approach (StoreKit 2)
760+
import {promotedProductListenerIOS, requestPurchase} from 'react-native-iap';
761+
762+
promotedProductListenerIOS(async (product) => {
763+
await requestPurchase({
764+
request: { apple: { sku: product.id } },
765+
type: 'in-app',
766+
});
767+
});
768+
769+
// Legacy approach (deprecated)
757770
import {requestPurchaseOnPromotedProductIOS} from 'react-native-iap';
758771

759-
await requestPurchaseOnPromotedProductIOS();
772+
const success = await requestPurchaseOnPromotedProductIOS();
760773
// Purchase result is delivered via purchase listeners/useIAP callbacks
761774
```
762775

763-
Returns: `Promise<void>`
776+
Returns: `Promise<boolean>` - `true` when the request triggers successfully
764777

765778
### getPendingTransactionsIOS()
766779

docs/docs/api/use-iap.md

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,10 @@ interface UseIAPOptions {
221221
// In hook: returns void. Listen via callbacks.
222222
await requestPurchase({
223223
request: {
224-
ios: {sku: productId},
225-
android: {skus: [productId]},
224+
apple: {sku: productId},
225+
google: {skus: [productId]},
226226
},
227+
type: 'in-app',
227228
});
228229
} catch (error) {
229230
console.error('Purchase request failed:', error);
@@ -258,8 +259,8 @@ const buySubscription = async (subscriptionId: string) => {
258259
// 3) Request purchase with offers
259260
await requestPurchase({
260261
request: {
261-
ios: {sku: subscriptionId},
262-
android: {
262+
apple: {sku: subscriptionId},
263+
google: {
263264
skus: [subscriptionId],
264265
// Only include subscriptionOffers when offers are available
265266
...(subscriptionOffers.length > 0 && {subscriptionOffers}),
@@ -283,12 +284,12 @@ const buySubscriptionWithOffer = async (
283284
) => {
284285
await requestPurchase({
285286
request: {
286-
ios: {
287+
apple: {
287288
sku: subscriptionId,
288289
// Optional: apply promotional offer
289290
...(discountOffer && {withOffer: discountOffer}),
290291
},
291-
android: {skus: [subscriptionId]},
292+
google: {skus: [subscriptionId]},
292293
},
293294
type: 'subs',
294295
});
@@ -436,16 +437,27 @@ const buySubscriptionWithOffer = async (
436437

437438
#### requestPurchaseOnPromotedProductIOS
438439

439-
- **Type**: `() => Promise<void>`
440+
- **Type**: `() => Promise<boolean>`
440441
- **Description**: Complete the purchase of a promoted product (iOS only)
441-
> Removed in v2.9.0: `buyPromotedProductIOS`. Use `requestPurchaseOnPromotedProductIOS` instead.
442+
> **Deprecated**: In StoreKit 2, promoted products can be purchased directly via the standard `requestPurchase()` flow. Use `promotedProductListenerIOS` to receive the product ID when a user taps a promoted product, then call `requestPurchase()` with the received SKU directly.
442443
- **Example**:
443444

444445
```tsx
446+
// Recommended approach (StoreKit 2)
447+
promotedProductListenerIOS(async (product) => {
448+
await requestPurchase({
449+
request: { apple: { sku: product.id } },
450+
type: 'in-app',
451+
});
452+
});
453+
454+
// Legacy approach (deprecated)
445455
const completePurchase = async () => {
446456
try {
447-
await requestPurchaseOnPromotedProductIOS();
448-
console.log('Promoted product purchase completed');
457+
const success = await requestPurchaseOnPromotedProductIOS();
458+
if (success) {
459+
console.log('Promoted product purchase completed');
460+
}
449461
} catch (error) {
450462
console.error('Failed to purchase promoted product:', error);
451463
}
@@ -471,9 +483,10 @@ const IOSPurchaseExample = () => {
471483
const buyProduct = (product: Product) => {
472484
requestPurchase({
473485
request: {
474-
ios: {sku: product.id},
475-
android: {skus: [product.id]},
486+
apple: {sku: product.id},
487+
google: {skus: [product.id]},
476488
},
489+
type: 'in-app',
477490
});
478491
};
479492
@@ -507,9 +520,10 @@ const AndroidPurchaseExample = () => {
507520
const buyProduct = (product: Product) => {
508521
requestPurchase({
509522
request: {
510-
ios: {sku: product.id},
511-
android: {skus: [product.id]},
523+
apple: {sku: product.id},
524+
google: {skus: [product.id]},
512525
},
526+
type: 'in-app',
513527
});
514528
};
515529
@@ -579,9 +593,10 @@ const {requestPurchase} = useIAP({
579593
try {
580594
await requestPurchase({
581595
request: {
582-
ios: {sku: productId},
583-
android: {skus: [productId]},
596+
apple: {sku: productId},
597+
google: {skus: [productId]},
584598
},
599+
type: 'in-app',
585600
});
586601
} finally {
587602
setLoading(false);

docs/docs/examples/purchase-flow.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ await fetchProducts({skus: ['product_id'], type: 'in-app'});
4242
// Purchase
4343
await requestPurchase({
4444
request: {
45-
ios: {sku: 'product_id'},
46-
android: {skus: ['product_id']},
45+
apple: {sku: 'product_id'},
46+
google: {skus: ['product_id']},
4747
},
4848
type: 'in-app',
4949
});

docs/docs/examples/subscription-flow.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ await fetchProducts({skus: ['premium_monthly'], type: 'subs'});
4343
const subscription = subscriptions[0];
4444
await requestPurchase({
4545
request: {
46-
ios: {sku: 'premium_monthly'},
47-
android: {
46+
apple: {sku: 'premium_monthly'},
47+
google: {
4848
skus: ['premium_monthly'],
4949
subscriptionOffers:
5050
subscription.subscriptionOfferDetailsAndroid?.map((offer) => ({
@@ -82,7 +82,7 @@ Requires explicit replacement with the current purchase token:
8282
```tsx
8383
await requestPurchase({
8484
request: {
85-
android: {
85+
google: {
8686
skus: ['premium_yearly'],
8787
subscriptionOffers: [...],
8888
purchaseTokenAndroid: currentPurchase.purchaseToken, // Required

docs/docs/getting-started/setup-ios.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ function App() {
7474
key={product.id}
7575
onPress={() =>
7676
requestPurchase({
77-
request: {ios: {sku: product.id}},
77+
request: {apple: {sku: product.id}},
78+
type: 'in-app',
7879
})
7980
}
8081
>
@@ -88,7 +89,7 @@ function App() {
8889
}
8990
```
9091

91-
> **💡 Cross-Platform Note:** This example shows iOS-specific usage with `sku`. For cross-platform compatibility, include both `sku` and `skus` in your request object. See the [Core Methods](/docs/api/methods/core-methods#requestpurchase) documentation for details.
92+
> **💡 Cross-Platform Note:** This example shows iOS-specific usage with `apple.sku`. For cross-platform compatibility, include both `apple` and `google` fields in your request object. The older `ios` and `android` fields are deprecated but still supported. See the [Core Methods](/docs/api/methods/core-methods#requestpurchase) documentation for details.
9293
9394
## Common Issues
9495

docs/docs/guides/lifecycle.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,10 @@ function ProductItem({productId}: {productId: string}) {
8080
try {
8181
await requestPurchase({
8282
request: {
83-
ios: {sku: productId},
84-
android: {skus: [productId]},
83+
apple: {sku: productId},
84+
google: {skus: [productId]},
8585
},
86+
type: 'in-app',
8687
});
8788
} catch (error) {
8889
console.error('Purchase request failed:', error);

0 commit comments

Comments
 (0)