expo-iap 2.9.6 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +24 -0
- package/CHANGELOG.md +43 -0
- package/README.md +1 -1
- package/android/build.gradle +7 -2
- package/android/src/main/java/expo/modules/iap/ExpoIapModule.kt +195 -668
- package/android/src/main/java/expo/modules/iap/PromiseUtils.kt +85 -0
- package/build/ExpoIap.types.d.ts +0 -6
- package/build/ExpoIap.types.d.ts.map +1 -1
- package/build/ExpoIap.types.js.map +1 -1
- package/build/helpers/subscription.d.ts.map +1 -1
- package/build/helpers/subscription.js +14 -3
- package/build/helpers/subscription.js.map +1 -1
- package/build/index.d.ts +6 -73
- package/build/index.d.ts.map +1 -1
- package/build/index.js +21 -154
- package/build/index.js.map +1 -1
- package/build/modules/android.d.ts +2 -2
- package/build/modules/android.d.ts.map +1 -1
- package/build/modules/android.js +11 -1
- package/build/modules/android.js.map +1 -1
- package/build/modules/ios.d.ts +0 -60
- package/build/modules/ios.d.ts.map +1 -1
- package/build/modules/ios.js +2 -121
- package/build/modules/ios.js.map +1 -1
- package/build/types/ExpoIapAndroid.types.d.ts +0 -8
- package/build/types/ExpoIapAndroid.types.d.ts.map +1 -1
- package/build/types/ExpoIapAndroid.types.js +0 -1
- package/build/types/ExpoIapAndroid.types.js.map +1 -1
- package/build/types/ExpoIapIOS.types.d.ts +0 -5
- package/build/types/ExpoIapIOS.types.d.ts.map +1 -1
- package/build/types/ExpoIapIOS.types.js.map +1 -1
- package/build/useIAP.d.ts +0 -18
- package/build/useIAP.d.ts.map +1 -1
- package/build/useIAP.js +1 -18
- package/build/useIAP.js.map +1 -1
- package/bun.lock +340 -137
- package/codecov.yml +17 -21
- package/ios/ExpoIapModule.swift +50 -23
- package/jest.config.js +5 -9
- package/package.json +5 -3
- package/plugin/build/withIAP.d.ts +4 -1
- package/plugin/build/withIAP.js +38 -24
- package/plugin/build/withLocalOpenIAP.d.ts +6 -2
- package/plugin/build/withLocalOpenIAP.js +175 -20
- package/plugin/src/withIAP.ts +66 -30
- package/plugin/src/withLocalOpenIAP.ts +228 -24
- package/src/ExpoIap.types.ts +0 -8
- package/src/helpers/subscription.ts +14 -3
- package/src/index.ts +22 -230
- package/src/modules/android.ts +16 -6
- package/src/modules/ios.ts +2 -168
- package/src/types/ExpoIapAndroid.types.ts +0 -11
- package/src/types/ExpoIapIOS.types.ts +0 -5
- package/src/useIAP.ts +3 -55
- package/android/src/main/java/expo/modules/iap/PlayUtils.kt +0 -178
- package/android/src/main/java/expo/modules/iap/Types.kt +0 -98
package/src/ExpoIap.types.ts
CHANGED
|
@@ -37,7 +37,6 @@ export type PurchaseCommon = {
|
|
|
37
37
|
id: string; // Transaction identifier - used by finishTransaction
|
|
38
38
|
productId: string; // Product identifier - which product was purchased
|
|
39
39
|
ids?: string[]; // Product identifiers for purchases that include multiple products
|
|
40
|
-
transactionId?: string; // @deprecated - use id instead
|
|
41
40
|
transactionDate: number;
|
|
42
41
|
transactionReceipt: string;
|
|
43
42
|
purchaseToken?: string; // Unified purchase token (jwsRepresentation for iOS, purchaseToken for Android)
|
|
@@ -70,17 +69,11 @@ export type Purchase =
|
|
|
70
69
|
| (PurchaseAndroid & AndroidPlatform)
|
|
71
70
|
| (PurchaseIOS & IosPlatform);
|
|
72
71
|
|
|
73
|
-
// Removed legacy type aliases `ProductPurchase` and `SubscriptionPurchase` in v2.9.0
|
|
74
|
-
|
|
75
72
|
export type PurchaseResult = {
|
|
76
73
|
responseCode?: number;
|
|
77
74
|
debugMessage?: string;
|
|
78
75
|
code?: string;
|
|
79
76
|
message?: string;
|
|
80
|
-
/**
|
|
81
|
-
* @deprecated Use `purchaseToken` instead. This field will be removed in a future version.
|
|
82
|
-
*/
|
|
83
|
-
purchaseTokenAndroid?: string;
|
|
84
77
|
purchaseToken?: string;
|
|
85
78
|
};
|
|
86
79
|
/**
|
|
@@ -399,7 +392,6 @@ export interface RequestPurchaseAndroidProps {
|
|
|
399
392
|
*/
|
|
400
393
|
export interface RequestSubscriptionAndroidProps
|
|
401
394
|
extends RequestPurchaseAndroidProps {
|
|
402
|
-
readonly purchaseTokenAndroid?: string;
|
|
403
395
|
readonly replacementModeAndroid?: number;
|
|
404
396
|
readonly subscriptionOffers: {
|
|
405
397
|
sku: string;
|
|
@@ -39,7 +39,8 @@ export const getActiveSubscriptions = async (
|
|
|
39
39
|
// Check if this purchase has subscription-specific fields
|
|
40
40
|
const hasSubscriptionFields =
|
|
41
41
|
('expirationDateIOS' in purchase && !!purchase.expirationDateIOS) ||
|
|
42
|
-
'autoRenewingAndroid' in purchase
|
|
42
|
+
'autoRenewingAndroid' in purchase ||
|
|
43
|
+
('environmentIOS' in purchase && !!(purchase as any).environmentIOS);
|
|
43
44
|
|
|
44
45
|
if (!hasSubscriptionFields) {
|
|
45
46
|
return false;
|
|
@@ -76,12 +77,22 @@ export const getActiveSubscriptions = async (
|
|
|
76
77
|
return false;
|
|
77
78
|
});
|
|
78
79
|
|
|
80
|
+
// Deduplicate by transaction identifier (id)
|
|
81
|
+
const seen = new Set<string>();
|
|
82
|
+
const dedupedPurchases = filteredPurchases.filter((p) => {
|
|
83
|
+
const key = String(p.id);
|
|
84
|
+
if (seen.has(key)) return false;
|
|
85
|
+
seen.add(key);
|
|
86
|
+
return true;
|
|
87
|
+
});
|
|
88
|
+
|
|
79
89
|
// Convert to ActiveSubscription format
|
|
80
|
-
for (const purchase of
|
|
90
|
+
for (const purchase of dedupedPurchases) {
|
|
81
91
|
const subscription: ActiveSubscription = {
|
|
82
92
|
productId: purchase.productId,
|
|
83
93
|
isActive: true,
|
|
84
|
-
|
|
94
|
+
// Use unified id as transaction identifier in v3
|
|
95
|
+
transactionId: purchase.id,
|
|
85
96
|
purchaseToken: purchase.purchaseToken,
|
|
86
97
|
transactionDate: purchase.transactionDate,
|
|
87
98
|
};
|
package/src/index.ts
CHANGED
|
@@ -49,8 +49,6 @@ export const PI = ExpoIapModule.PI;
|
|
|
49
49
|
export enum OpenIapEvent {
|
|
50
50
|
PurchaseUpdated = 'purchase-updated',
|
|
51
51
|
PurchaseError = 'purchase-error',
|
|
52
|
-
/** @deprecated Use PurchaseUpdated instead. This will be removed in a future version. */
|
|
53
|
-
TransactionIapUpdated = 'iap-transaction-updated',
|
|
54
52
|
PromotedProductIOS = 'promoted-product-ios',
|
|
55
53
|
}
|
|
56
54
|
|
|
@@ -139,89 +137,6 @@ export function initConnection(): Promise<boolean> {
|
|
|
139
137
|
return Promise.resolve(result);
|
|
140
138
|
}
|
|
141
139
|
|
|
142
|
-
export const getProducts = async (skus: string[]): Promise<Product[]> => {
|
|
143
|
-
console.warn(
|
|
144
|
-
"`getProducts` is deprecated. Use `fetchProducts({ skus, type: 'inapp' })` instead. This function will be removed in version 3.0.0.",
|
|
145
|
-
);
|
|
146
|
-
if (!skus?.length) {
|
|
147
|
-
return Promise.reject(
|
|
148
|
-
new PurchaseError({
|
|
149
|
-
message: 'No SKUs provided',
|
|
150
|
-
code: ErrorCode.E_EMPTY_SKU_LIST,
|
|
151
|
-
}),
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return Platform.select({
|
|
156
|
-
ios: async () => {
|
|
157
|
-
const rawItems = await ExpoIapModule.fetchProducts(skus);
|
|
158
|
-
return rawItems.filter((item: unknown) => {
|
|
159
|
-
if (!isProductIOS(item)) return false;
|
|
160
|
-
return (
|
|
161
|
-
typeof item === 'object' &&
|
|
162
|
-
item !== null &&
|
|
163
|
-
'id' in item &&
|
|
164
|
-
typeof item.id === 'string' &&
|
|
165
|
-
skus.includes(item.id)
|
|
166
|
-
);
|
|
167
|
-
}) as Product[];
|
|
168
|
-
},
|
|
169
|
-
android: async () => {
|
|
170
|
-
const products = await ExpoIapModule.fetchProducts('inapp', skus);
|
|
171
|
-
return products.filter((product: unknown) =>
|
|
172
|
-
isProductAndroid<Product>(product),
|
|
173
|
-
);
|
|
174
|
-
},
|
|
175
|
-
default: () => Promise.reject(new Error('Unsupported Platform')),
|
|
176
|
-
})();
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
export const getSubscriptions = async (
|
|
180
|
-
skus: string[],
|
|
181
|
-
): Promise<SubscriptionProduct[]> => {
|
|
182
|
-
console.warn(
|
|
183
|
-
"`getSubscriptions` is deprecated. Use `fetchProducts({ skus, type: 'subs' })` instead. This function will be removed in version 3.0.0.",
|
|
184
|
-
);
|
|
185
|
-
if (!skus?.length) {
|
|
186
|
-
return Promise.reject(
|
|
187
|
-
new PurchaseError({
|
|
188
|
-
message: 'No SKUs provided',
|
|
189
|
-
code: ErrorCode.E_EMPTY_SKU_LIST,
|
|
190
|
-
}),
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return Platform.select({
|
|
195
|
-
ios: async () => {
|
|
196
|
-
const rawItems = await ExpoIapModule.fetchProducts(skus);
|
|
197
|
-
return rawItems.filter((item: unknown) => {
|
|
198
|
-
if (!isProductIOS(item)) return false;
|
|
199
|
-
return (
|
|
200
|
-
typeof item === 'object' &&
|
|
201
|
-
item !== null &&
|
|
202
|
-
'id' in item &&
|
|
203
|
-
typeof item.id === 'string' &&
|
|
204
|
-
skus.includes(item.id)
|
|
205
|
-
);
|
|
206
|
-
}) as SubscriptionProduct[];
|
|
207
|
-
},
|
|
208
|
-
android: async () => {
|
|
209
|
-
const rawItems = await ExpoIapModule.fetchProducts('subs', skus);
|
|
210
|
-
return rawItems.filter((item: unknown) => {
|
|
211
|
-
if (!isProductAndroid(item)) return false;
|
|
212
|
-
return (
|
|
213
|
-
typeof item === 'object' &&
|
|
214
|
-
item !== null &&
|
|
215
|
-
'id' in item &&
|
|
216
|
-
typeof item.id === 'string' &&
|
|
217
|
-
skus.includes(item.id)
|
|
218
|
-
);
|
|
219
|
-
}) as SubscriptionProduct[];
|
|
220
|
-
},
|
|
221
|
-
default: () => Promise.reject(new Error('Unsupported Platform')),
|
|
222
|
-
})();
|
|
223
|
-
};
|
|
224
|
-
|
|
225
140
|
export async function endConnection(): Promise<boolean> {
|
|
226
141
|
return ExpoIapModule.endConnection();
|
|
227
142
|
}
|
|
@@ -304,81 +219,10 @@ export const fetchProducts = async ({
|
|
|
304
219
|
throw new Error('Unsupported platform');
|
|
305
220
|
};
|
|
306
221
|
|
|
307
|
-
/**
|
|
308
|
-
* @deprecated Use `fetchProducts` instead. This method will be removed in version 3.0.0.
|
|
309
|
-
*
|
|
310
|
-
* The 'request' prefix should only be used for event-based operations that trigger
|
|
311
|
-
* purchase flows. Since this function simply fetches product information, it has been
|
|
312
|
-
* renamed to `fetchProducts` to follow OpenIAP terminology guidelines.
|
|
313
|
-
*
|
|
314
|
-
* @example
|
|
315
|
-
* ```typescript
|
|
316
|
-
* // Old way (deprecated)
|
|
317
|
-
* const products = await requestProducts({
|
|
318
|
-
* skus: ['com.example.product1'],
|
|
319
|
-
* type: 'inapp'
|
|
320
|
-
* });
|
|
321
|
-
*
|
|
322
|
-
* // New way (recommended)
|
|
323
|
-
* const products = await fetchProducts({
|
|
324
|
-
* skus: ['com.example.product1'],
|
|
325
|
-
* type: 'inapp'
|
|
326
|
-
* });
|
|
327
|
-
* ```
|
|
328
|
-
*/
|
|
329
|
-
export const requestProducts = async ({
|
|
330
|
-
skus,
|
|
331
|
-
type = 'inapp',
|
|
332
|
-
}: {
|
|
333
|
-
skus: string[];
|
|
334
|
-
type?: 'inapp' | 'subs';
|
|
335
|
-
}): Promise<Product[] | SubscriptionProduct[]> => {
|
|
336
|
-
console.warn(
|
|
337
|
-
"`requestProducts` is deprecated. Use `fetchProducts` instead. The 'request' prefix should only be used for event-based operations. This method will be removed in version 3.0.0.",
|
|
338
|
-
);
|
|
339
|
-
return fetchProducts({skus, type});
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* @deprecated Use `getPurchaseHistories` instead. This function will be removed in version 3.0.0.
|
|
344
|
-
*/
|
|
345
|
-
export const getPurchaseHistory = ({
|
|
346
|
-
alsoPublishToEventListener = false,
|
|
347
|
-
onlyIncludeActiveItems = false,
|
|
348
|
-
alsoPublishToEventListenerIOS,
|
|
349
|
-
onlyIncludeActiveItemsIOS,
|
|
350
|
-
}: {
|
|
351
|
-
/** @deprecated Use alsoPublishToEventListenerIOS instead */
|
|
352
|
-
alsoPublishToEventListener?: boolean;
|
|
353
|
-
/** @deprecated Use onlyIncludeActiveItemsIOS instead */
|
|
354
|
-
onlyIncludeActiveItems?: boolean;
|
|
355
|
-
alsoPublishToEventListenerIOS?: boolean;
|
|
356
|
-
onlyIncludeActiveItemsIOS?: boolean;
|
|
357
|
-
} = {}): Promise<Purchase[]> => {
|
|
358
|
-
console.warn(
|
|
359
|
-
'`getPurchaseHistory` is deprecated. Use `getPurchaseHistories` instead. This function will be removed in version 3.0.0.',
|
|
360
|
-
);
|
|
361
|
-
// Use available purchases as a best-effort replacement
|
|
362
|
-
return getAvailablePurchases({
|
|
363
|
-
alsoPublishToEventListenerIOS:
|
|
364
|
-
alsoPublishToEventListenerIOS ?? alsoPublishToEventListener,
|
|
365
|
-
onlyIncludeActiveItemsIOS:
|
|
366
|
-
onlyIncludeActiveItemsIOS ?? onlyIncludeActiveItems,
|
|
367
|
-
});
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
// NOTE: `getPurchaseHistories` removed in v2.9.0. Use `getAvailablePurchases` instead.
|
|
371
|
-
|
|
372
222
|
export const getAvailablePurchases = ({
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
alsoPublishToEventListenerIOS,
|
|
376
|
-
onlyIncludeActiveItemsIOS,
|
|
223
|
+
alsoPublishToEventListenerIOS = false,
|
|
224
|
+
onlyIncludeActiveItemsIOS = true,
|
|
377
225
|
}: {
|
|
378
|
-
/** @deprecated Use alsoPublishToEventListenerIOS instead */
|
|
379
|
-
alsoPublishToEventListener?: boolean;
|
|
380
|
-
/** @deprecated Use onlyIncludeActiveItemsIOS instead */
|
|
381
|
-
onlyIncludeActiveItems?: boolean;
|
|
382
226
|
alsoPublishToEventListenerIOS?: boolean;
|
|
383
227
|
onlyIncludeActiveItemsIOS?: boolean;
|
|
384
228
|
} = {}): Promise<Purchase[]> =>
|
|
@@ -386,16 +230,10 @@ export const getAvailablePurchases = ({
|
|
|
386
230
|
Platform.select({
|
|
387
231
|
ios: () =>
|
|
388
232
|
ExpoIapModule.getAvailableItems(
|
|
389
|
-
alsoPublishToEventListenerIOS
|
|
390
|
-
onlyIncludeActiveItemsIOS
|
|
233
|
+
alsoPublishToEventListenerIOS,
|
|
234
|
+
onlyIncludeActiveItemsIOS,
|
|
391
235
|
),
|
|
392
|
-
android:
|
|
393
|
-
const products = await ExpoIapModule.getAvailableItemsByType('inapp');
|
|
394
|
-
const subscriptions = await ExpoIapModule.getAvailableItemsByType(
|
|
395
|
-
'subs',
|
|
396
|
-
);
|
|
397
|
-
return products.concat(subscriptions);
|
|
398
|
-
},
|
|
236
|
+
android: () => ExpoIapModule.getAvailableItems(),
|
|
399
237
|
}) || (() => Promise.resolve([]))
|
|
400
238
|
)();
|
|
401
239
|
|
|
@@ -574,7 +412,6 @@ export const requestPurchase = (
|
|
|
574
412
|
isOfferPersonalized,
|
|
575
413
|
subscriptionOffers = [],
|
|
576
414
|
replacementModeAndroid = -1,
|
|
577
|
-
purchaseTokenAndroid,
|
|
578
415
|
purchaseToken,
|
|
579
416
|
} = normalizedRequest;
|
|
580
417
|
|
|
@@ -582,7 +419,7 @@ export const requestPurchase = (
|
|
|
582
419
|
return ExpoIapModule.requestPurchase({
|
|
583
420
|
type: 'subs',
|
|
584
421
|
skuArr: skus,
|
|
585
|
-
purchaseToken
|
|
422
|
+
purchaseToken,
|
|
586
423
|
replacementMode: replacementModeAndroid,
|
|
587
424
|
obfuscatedAccountId: obfuscatedAccountIdAndroid,
|
|
588
425
|
obfuscatedProfileId: obfuscatedProfileIdAndroid,
|
|
@@ -600,44 +437,6 @@ export const requestPurchase = (
|
|
|
600
437
|
return Promise.resolve(); // Fallback for unsupported platforms
|
|
601
438
|
};
|
|
602
439
|
|
|
603
|
-
/**
|
|
604
|
-
* @deprecated Use `requestPurchase({ request, type: 'subs' })` instead. This method will be removed in version 3.0.0.
|
|
605
|
-
*
|
|
606
|
-
* @example
|
|
607
|
-
* ```typescript
|
|
608
|
-
* // Old way (deprecated)
|
|
609
|
-
* await requestSubscription({
|
|
610
|
-
* sku: subscriptionId,
|
|
611
|
-
* // or for Android
|
|
612
|
-
* skus: [subscriptionId],
|
|
613
|
-
* });
|
|
614
|
-
*
|
|
615
|
-
* // New way (recommended)
|
|
616
|
-
* await requestPurchase({
|
|
617
|
-
* request: {
|
|
618
|
-
* ios: { sku: subscriptionId },
|
|
619
|
-
* android: {
|
|
620
|
-
* skus: [subscriptionId],
|
|
621
|
-
* subscriptionOffers: [{ sku: subscriptionId, offerToken: 'token' }]
|
|
622
|
-
* }
|
|
623
|
-
* },
|
|
624
|
-
* type: 'subs'
|
|
625
|
-
* });
|
|
626
|
-
* ```
|
|
627
|
-
*/
|
|
628
|
-
export const requestSubscription = async (
|
|
629
|
-
request: RequestSubscriptionProps,
|
|
630
|
-
): Promise<Purchase | Purchase[] | null | void> => {
|
|
631
|
-
console.warn(
|
|
632
|
-
"`requestSubscription` is deprecated and will be removed in version 3.0.0. Use `requestPurchase({ request, type: 'subs' })` instead.",
|
|
633
|
-
);
|
|
634
|
-
return (await requestPurchase({request, type: 'subs'})) as
|
|
635
|
-
| Purchase
|
|
636
|
-
| Purchase[]
|
|
637
|
-
| null
|
|
638
|
-
| void;
|
|
639
|
-
};
|
|
640
|
-
|
|
641
440
|
export const finishTransaction = ({
|
|
642
441
|
purchase,
|
|
643
442
|
isConsumable = false,
|
|
@@ -661,8 +460,7 @@ export const finishTransaction = ({
|
|
|
661
460
|
const androidPurchase = purchase as PurchaseAndroid;
|
|
662
461
|
|
|
663
462
|
// Use purchaseToken if available, fallback to purchaseTokenAndroid for backward compatibility
|
|
664
|
-
const token =
|
|
665
|
-
androidPurchase.purchaseToken || androidPurchase.purchaseTokenAndroid;
|
|
463
|
+
const token = androidPurchase.purchaseToken;
|
|
666
464
|
|
|
667
465
|
if (!token) {
|
|
668
466
|
return Promise.reject(
|
|
@@ -676,7 +474,7 @@ export const finishTransaction = ({
|
|
|
676
474
|
}
|
|
677
475
|
|
|
678
476
|
if (isConsumable) {
|
|
679
|
-
return ExpoIapModule.
|
|
477
|
+
return ExpoIapModule.consumePurchaseAndroid(token);
|
|
680
478
|
}
|
|
681
479
|
|
|
682
480
|
return ExpoIapModule.acknowledgePurchaseAndroid(token);
|
|
@@ -708,12 +506,20 @@ export const getStorefrontIOS = (): Promise<string> => {
|
|
|
708
506
|
};
|
|
709
507
|
|
|
710
508
|
/**
|
|
711
|
-
*
|
|
509
|
+
* Gets the storefront country code from the underlying native store.
|
|
510
|
+
* Returns a two-letter country code such as 'US', 'KR', or empty string on failure.
|
|
511
|
+
*
|
|
512
|
+
* @platform ios
|
|
513
|
+
* @platform android
|
|
712
514
|
*/
|
|
713
515
|
export const getStorefront = (): Promise<string> => {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
516
|
+
// Cross-platform storefront
|
|
517
|
+
if (Platform.OS === 'android') {
|
|
518
|
+
if (typeof (ExpoIapModule as any).getStorefrontAndroid === 'function') {
|
|
519
|
+
return (ExpoIapModule as any).getStorefrontAndroid();
|
|
520
|
+
}
|
|
521
|
+
return Promise.resolve('');
|
|
522
|
+
}
|
|
717
523
|
return getStorefrontIOS();
|
|
718
524
|
};
|
|
719
525
|
|
|
@@ -786,23 +592,9 @@ export const deepLinkToSubscriptions = (options: {
|
|
|
786
592
|
}
|
|
787
593
|
|
|
788
594
|
if (Platform.OS === 'android') {
|
|
789
|
-
if (!options.skuAndroid) {
|
|
790
|
-
return Promise.reject(
|
|
791
|
-
new Error(
|
|
792
|
-
'skuAndroid is required to locate subscription in Android Store',
|
|
793
|
-
),
|
|
794
|
-
);
|
|
795
|
-
}
|
|
796
|
-
if (!options.packageNameAndroid) {
|
|
797
|
-
return Promise.reject(
|
|
798
|
-
new Error(
|
|
799
|
-
'packageNameAndroid is required to identify your app in Android Store',
|
|
800
|
-
),
|
|
801
|
-
);
|
|
802
|
-
}
|
|
803
595
|
return deepLinkToSubscriptionsAndroid({
|
|
804
|
-
sku: options
|
|
805
|
-
packageName: options
|
|
596
|
+
sku: options?.skuAndroid,
|
|
597
|
+
packageName: options?.packageNameAndroid,
|
|
806
598
|
});
|
|
807
599
|
}
|
|
808
600
|
|
package/src/modules/android.ts
CHANGED
|
@@ -38,18 +38,28 @@ export const deepLinkToSubscriptionsAndroid = async ({
|
|
|
38
38
|
sku,
|
|
39
39
|
packageName,
|
|
40
40
|
}: {
|
|
41
|
-
sku
|
|
42
|
-
packageName
|
|
41
|
+
sku?: string;
|
|
42
|
+
packageName?: string;
|
|
43
43
|
}): Promise<void> => {
|
|
44
|
+
// Prefer native deep link implementation via OpenIAP module
|
|
45
|
+
if (ExpoIapModule?.deepLinkToSubscriptionsAndroid) {
|
|
46
|
+
return (ExpoIapModule as any).deepLinkToSubscriptionsAndroid({
|
|
47
|
+
skuAndroid: sku,
|
|
48
|
+
packageNameAndroid: packageName,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Fallback to Linking if native method unavailable
|
|
44
53
|
if (!packageName) {
|
|
45
54
|
throw new Error(
|
|
46
55
|
'packageName is required for deepLinkToSubscriptionsAndroid',
|
|
47
56
|
);
|
|
48
57
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
58
|
+
const base = `https://play.google.com/store/account/subscriptions?package=${encodeURIComponent(
|
|
59
|
+
packageName,
|
|
60
|
+
)}`;
|
|
61
|
+
const url = sku ? `${base}&sku=${encodeURIComponent(sku)}` : base;
|
|
62
|
+
return Linking.openURL(url);
|
|
53
63
|
};
|
|
54
64
|
|
|
55
65
|
/**
|
package/src/modules/ios.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// External dependencies
|
|
2
2
|
|
|
3
3
|
// Internal modules
|
|
4
|
-
import
|
|
4
|
+
// import removed: use purchaseUpdatedListener directly in app code
|
|
5
5
|
import ExpoIapModule from '../ExpoIapModule';
|
|
6
6
|
|
|
7
7
|
// Types
|
|
@@ -20,55 +20,6 @@ export type TransactionEvent = {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
// Listeners
|
|
23
|
-
/**
|
|
24
|
-
* @deprecated Use `purchaseUpdatedListener` instead. This function will be removed in a future version.
|
|
25
|
-
*
|
|
26
|
-
* The `transactionUpdatedIos` function is redundant as it simply wraps `purchaseUpdatedListener`.
|
|
27
|
-
* You can achieve the same functionality by using `purchaseUpdatedListener` directly.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* // Instead of:
|
|
31
|
-
* // transactionUpdatedIos((event) => { ... });
|
|
32
|
-
*
|
|
33
|
-
* // Use:
|
|
34
|
-
* // purchaseUpdatedListener((purchase) => { ... });
|
|
35
|
-
*/
|
|
36
|
-
export const transactionUpdatedIOS = (
|
|
37
|
-
listener: (event: TransactionEvent) => void,
|
|
38
|
-
) => {
|
|
39
|
-
const isPurchase = (item: unknown): item is Purchase => {
|
|
40
|
-
return (
|
|
41
|
-
item != null &&
|
|
42
|
-
typeof item === 'object' &&
|
|
43
|
-
'id' in item &&
|
|
44
|
-
'transactionId' in item &&
|
|
45
|
-
'platform' in item
|
|
46
|
-
);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// Helper function to safely convert Purchase to TransactionEvent
|
|
50
|
-
const mapPurchaseToTransactionEvent = (
|
|
51
|
-
purchase: Purchase,
|
|
52
|
-
): TransactionEvent => {
|
|
53
|
-
// Validate the purchase object before casting
|
|
54
|
-
if (isPurchase(purchase)) {
|
|
55
|
-
return {
|
|
56
|
-
transaction: purchase as Purchase,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Fallback: create a basic TransactionEvent structure
|
|
61
|
-
return {
|
|
62
|
-
transaction: purchase as Purchase,
|
|
63
|
-
};
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
return purchaseUpdatedListener((purchase) => {
|
|
67
|
-
// Convert Purchase to TransactionEvent format for backward compatibility
|
|
68
|
-
const event = mapPurchaseToTransactionEvent(purchase);
|
|
69
|
-
listener(event);
|
|
70
|
-
});
|
|
71
|
-
};
|
|
72
23
|
|
|
73
24
|
// Type guards
|
|
74
25
|
export function isProductIOS<T extends {platform?: string}>(
|
|
@@ -310,8 +261,6 @@ export const requestPurchaseOnPromotedProductIOS = (): Promise<void> => {
|
|
|
310
261
|
return ExpoIapModule.requestPurchaseOnPromotedProductIOS();
|
|
311
262
|
};
|
|
312
263
|
|
|
313
|
-
// NOTE: buyPromotedProductIOS removed in v2.9.0. Use requestPurchaseOnPromotedProductIOS.
|
|
314
|
-
|
|
315
264
|
/**
|
|
316
265
|
* Get pending transactions that haven't been finished yet (iOS only).
|
|
317
266
|
*
|
|
@@ -341,119 +290,4 @@ export const clearTransactionIOS = (): Promise<void> => {
|
|
|
341
290
|
export const deepLinkToSubscriptionsIOS = (): Promise<void> =>
|
|
342
291
|
Linking.openURL('https://apps.apple.com/account/subscriptions');
|
|
343
292
|
|
|
344
|
-
//
|
|
345
|
-
// These will be removed in version 3.0.0
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* @deprecated Use `syncIOS` instead. This function will be removed in version 3.0.0.
|
|
349
|
-
*/
|
|
350
|
-
export const sync = (): Promise<null> => {
|
|
351
|
-
console.warn(
|
|
352
|
-
'`sync` is deprecated. Use `syncIOS` instead. This function will be removed in version 3.0.0.',
|
|
353
|
-
);
|
|
354
|
-
return syncIOS();
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* @deprecated Use `isEligibleForIntroOfferIOS` instead. This function will be removed in version 3.0.0.
|
|
359
|
-
*/
|
|
360
|
-
export const isEligibleForIntroOffer = (groupId: string): Promise<boolean> => {
|
|
361
|
-
console.warn(
|
|
362
|
-
'`isEligibleForIntroOffer` is deprecated. Use `isEligibleForIntroOfferIOS` instead. This function will be removed in version 3.0.0.',
|
|
363
|
-
);
|
|
364
|
-
return isEligibleForIntroOfferIOS(groupId);
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* @deprecated Use `subscriptionStatusIOS` instead. This function will be removed in version 3.0.0.
|
|
369
|
-
*/
|
|
370
|
-
export const subscriptionStatus = (
|
|
371
|
-
sku: string,
|
|
372
|
-
): Promise<SubscriptionStatusIOS[]> => {
|
|
373
|
-
console.warn(
|
|
374
|
-
'`subscriptionStatus` is deprecated. Use `subscriptionStatusIOS` instead. This function will be removed in version 3.0.0.',
|
|
375
|
-
);
|
|
376
|
-
return subscriptionStatusIOS(sku);
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* @deprecated Use `currentEntitlementIOS` instead. This function will be removed in version 3.0.0.
|
|
381
|
-
*/
|
|
382
|
-
export const currentEntitlement = (sku: string): Promise<Purchase> => {
|
|
383
|
-
console.warn(
|
|
384
|
-
'`currentEntitlement` is deprecated. Use `currentEntitlementIOS` instead. This function will be removed in version 3.0.0.',
|
|
385
|
-
);
|
|
386
|
-
return currentEntitlementIOS(sku);
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* @deprecated Use `latestTransactionIOS` instead. This function will be removed in version 3.0.0.
|
|
391
|
-
*/
|
|
392
|
-
export const latestTransaction = (sku: string): Promise<Purchase> => {
|
|
393
|
-
console.warn(
|
|
394
|
-
'`latestTransaction` is deprecated. Use `latestTransactionIOS` instead. This function will be removed in version 3.0.0.',
|
|
395
|
-
);
|
|
396
|
-
return latestTransactionIOS(sku);
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* @deprecated Use `beginRefundRequestIOS` instead. This function will be removed in version 3.0.0.
|
|
401
|
-
*/
|
|
402
|
-
export const beginRefundRequest = (
|
|
403
|
-
sku: string,
|
|
404
|
-
): Promise<RefundRequestStatus> => {
|
|
405
|
-
console.warn(
|
|
406
|
-
'`beginRefundRequest` is deprecated. Use `beginRefundRequestIOS` instead. This function will be removed in version 3.0.0.',
|
|
407
|
-
);
|
|
408
|
-
return beginRefundRequestIOS(sku);
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* @deprecated Use `showManageSubscriptionsIOS` instead. This function will be removed in version 3.0.0.
|
|
413
|
-
*/
|
|
414
|
-
export const showManageSubscriptions = (): Promise<Purchase[]> => {
|
|
415
|
-
console.warn(
|
|
416
|
-
'`showManageSubscriptions` is deprecated. Use `showManageSubscriptionsIOS` instead. This function will be removed in version 3.0.0.',
|
|
417
|
-
);
|
|
418
|
-
return showManageSubscriptionsIOS();
|
|
419
|
-
};
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* @deprecated Use `isTransactionVerifiedIOS` instead. This function will be removed in version 3.0.0.
|
|
423
|
-
*/
|
|
424
|
-
export const isTransactionVerified = (sku: string): Promise<boolean> => {
|
|
425
|
-
console.warn(
|
|
426
|
-
'`isTransactionVerified` is deprecated. Use `isTransactionVerifiedIOS` instead. This function will be removed in version 3.0.0.',
|
|
427
|
-
);
|
|
428
|
-
return isTransactionVerifiedIOS(sku);
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* @deprecated Use `getTransactionJwsIOS` instead. This function will be removed in version 3.0.0.
|
|
433
|
-
*/
|
|
434
|
-
export const getTransactionJws = (sku: string): Promise<string> => {
|
|
435
|
-
console.warn(
|
|
436
|
-
'`getTransactionJws` is deprecated. Use `getTransactionJwsIOS` instead. This function will be removed in version 3.0.0.',
|
|
437
|
-
);
|
|
438
|
-
return getTransactionJwsIOS(sku);
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* @deprecated Use `presentCodeRedemptionSheetIOS` instead. This function will be removed in version 3.0.0.
|
|
443
|
-
*/
|
|
444
|
-
export const presentCodeRedemptionSheet = (): Promise<boolean> => {
|
|
445
|
-
console.warn(
|
|
446
|
-
'`presentCodeRedemptionSheet` is deprecated. Use `presentCodeRedemptionSheetIOS` instead. This function will be removed in version 3.0.0.',
|
|
447
|
-
);
|
|
448
|
-
return presentCodeRedemptionSheetIOS();
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* @deprecated Use `getAppTransactionIOS` instead. This function will be removed in version 3.0.0.
|
|
453
|
-
*/
|
|
454
|
-
export const getAppTransaction = (): Promise<AppTransactionIOS | null> => {
|
|
455
|
-
console.warn(
|
|
456
|
-
'`getAppTransaction` is deprecated. Use `getAppTransactionIOS` instead. This function will be removed in version 3.0.0.',
|
|
457
|
-
);
|
|
458
|
-
return getAppTransactionIOS();
|
|
459
|
-
};
|
|
293
|
+
// iOS-specific APIs only; cross-platform wrappers live in src/index.ts
|
|
@@ -72,10 +72,6 @@ type SubscriptionOffer = {
|
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
export type RequestSubscriptionAndroidProps = RequestPurchaseAndroidProps & {
|
|
75
|
-
/**
|
|
76
|
-
* @deprecated Use `purchaseToken` instead. This field will be removed in a future version.
|
|
77
|
-
*/
|
|
78
|
-
purchaseTokenAndroid?: string;
|
|
79
75
|
replacementModeAndroid?: ReplacementModesAndroid;
|
|
80
76
|
subscriptionOffers: SubscriptionOffer[];
|
|
81
77
|
};
|
|
@@ -121,15 +117,10 @@ export enum PurchaseAndroidState {
|
|
|
121
117
|
}
|
|
122
118
|
|
|
123
119
|
// Legacy naming for backward compatibility
|
|
124
|
-
// Removed legacy alias `PurchaseStateAndroid` in v2.9.0
|
|
125
120
|
|
|
126
121
|
// Legacy naming for backward compatibility
|
|
127
122
|
export type ProductPurchaseAndroid = PurchaseCommon & {
|
|
128
123
|
platform: 'android';
|
|
129
|
-
/**
|
|
130
|
-
* @deprecated Use `purchaseToken` instead. This field will be removed in a future version.
|
|
131
|
-
*/
|
|
132
|
-
purchaseTokenAndroid?: string;
|
|
133
124
|
dataAndroid?: string;
|
|
134
125
|
signatureAndroid?: string;
|
|
135
126
|
autoRenewingAndroid?: boolean;
|
|
@@ -143,5 +134,3 @@ export type ProductPurchaseAndroid = PurchaseCommon & {
|
|
|
143
134
|
|
|
144
135
|
// Preferred naming
|
|
145
136
|
export type PurchaseAndroid = ProductPurchaseAndroid;
|
|
146
|
-
|
|
147
|
-
// Removed legacy Android alias types in v2.9.0
|
|
@@ -145,11 +145,6 @@ export type ProductPurchaseIOS = PurchaseCommon & {
|
|
|
145
145
|
currencyCodeIOS?: string;
|
|
146
146
|
currencySymbolIOS?: string;
|
|
147
147
|
countryCodeIOS?: string;
|
|
148
|
-
/**
|
|
149
|
-
* @deprecated Use `purchaseToken` instead. This field will be removed in a future version.
|
|
150
|
-
* iOS 15+ JWS representation is now available through the `purchaseToken` field.
|
|
151
|
-
*/
|
|
152
|
-
jwsRepresentationIOS?: string;
|
|
153
148
|
};
|
|
154
149
|
|
|
155
150
|
// Preferred naming
|