expo-iap 3.1.4 → 3.1.6
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/android/src/main/java/expo/modules/iap/ExpoIapModule.kt +5 -5
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -7
- package/build/index.js.map +1 -1
- package/build/modules/android.d.ts.map +1 -1
- package/build/modules/android.js +3 -2
- package/build/modules/android.js.map +1 -1
- package/build/modules/ios.d.ts +0 -15
- package/build/modules/ios.d.ts.map +1 -1
- package/build/modules/ios.js +1 -22
- package/build/modules/ios.js.map +1 -1
- package/build/types.d.ts +7 -1
- package/build/types.d.ts.map +1 -1
- package/build/types.js.map +1 -1
- package/build/useIAP.d.ts.map +1 -1
- package/build/useIAP.js +25 -2
- package/build/useIAP.js.map +1 -1
- package/coverage/clover.xml +236 -242
- package/coverage/coverage-final.json +3 -3
- package/coverage/lcov-report/index.html +22 -22
- package/coverage/lcov-report/src/helpers/index.html +1 -1
- package/coverage/lcov-report/src/helpers/subscription.ts.html +1 -1
- package/coverage/lcov-report/src/index.html +15 -15
- package/coverage/lcov-report/src/index.ts.html +13 -28
- package/coverage/lcov-report/src/modules/android.ts.html +36 -6
- package/coverage/lcov-report/src/modules/index.html +12 -12
- package/coverage/lcov-report/src/modules/ios.ts.html +7 -73
- package/coverage/lcov-report/src/utils/errorMapping.ts.html +1 -1
- package/coverage/lcov-report/src/utils/index.html +1 -1
- package/coverage/lcov.info +414 -422
- package/ios/ExpoIapModule.swift +3 -3
- package/openiap-versions.json +3 -3
- package/package.json +1 -1
- package/src/index.ts +3 -8
- package/src/modules/android.ts +12 -2
- package/src/modules/ios.ts +1 -23
- package/src/types.ts +7 -1
- package/src/useIAP.ts +39 -6
package/ios/ExpoIapModule.swift
CHANGED
|
@@ -246,11 +246,11 @@ public final class ExpoIapModule: Module {
|
|
|
246
246
|
return nil
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
AsyncFunction("
|
|
250
|
-
ExpoIapLog.payload("
|
|
249
|
+
AsyncFunction("getStorefront") { () async throws -> String in
|
|
250
|
+
ExpoIapLog.payload("getStorefront", payload: nil)
|
|
251
251
|
try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
|
|
252
252
|
let storefront = try await OpenIapModule.shared.getStorefrontIOS()
|
|
253
|
-
ExpoIapLog.result("
|
|
253
|
+
ExpoIapLog.result("getStorefront", value: storefront)
|
|
254
254
|
return storefront
|
|
255
255
|
}
|
|
256
256
|
|
package/openiap-versions.json
CHANGED
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
validateReceiptIOS,
|
|
10
10
|
deepLinkToSubscriptionsIOS,
|
|
11
11
|
syncIOS,
|
|
12
|
-
getStorefrontIOS,
|
|
13
12
|
} from './modules/ios';
|
|
14
13
|
import {
|
|
15
14
|
isProductAndroid,
|
|
@@ -292,15 +291,11 @@ export const getAvailablePurchases: QueryField<
|
|
|
292
291
|
return normalizePurchaseArray(purchases as Purchase[]);
|
|
293
292
|
};
|
|
294
293
|
|
|
295
|
-
export const getStorefront: QueryField<'
|
|
296
|
-
|
|
297
|
-
if (Platform.OS === 'android') {
|
|
298
|
-
if (typeof ExpoIapModule.getStorefrontAndroid === 'function') {
|
|
299
|
-
return ExpoIapModule.getStorefrontAndroid();
|
|
300
|
-
}
|
|
294
|
+
export const getStorefront: QueryField<'getStorefront'> = async () => {
|
|
295
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
|
|
301
296
|
return '';
|
|
302
297
|
}
|
|
303
|
-
return
|
|
298
|
+
return ExpoIapModule.getStorefront();
|
|
304
299
|
};
|
|
305
300
|
|
|
306
301
|
/**
|
package/src/modules/android.ts
CHANGED
|
@@ -11,6 +11,16 @@ import type {
|
|
|
11
11
|
ReceiptValidationResultAndroid,
|
|
12
12
|
} from '../types';
|
|
13
13
|
|
|
14
|
+
type NativeAndroidModule = {
|
|
15
|
+
deepLinkToSubscriptionsAndroid?: (params: {
|
|
16
|
+
skuAndroid?: string;
|
|
17
|
+
packageNameAndroid?: string;
|
|
18
|
+
}) => Promise<void> | void;
|
|
19
|
+
getStorefront?: () => Promise<string> | string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const nativeAndroidModule = ExpoIapModule as NativeAndroidModule;
|
|
23
|
+
|
|
14
24
|
// Type guards
|
|
15
25
|
export function isProductAndroid<T extends {platform?: string}>(
|
|
16
26
|
item: unknown,
|
|
@@ -46,8 +56,8 @@ export const deepLinkToSubscriptionsAndroid = async (
|
|
|
46
56
|
const packageName = options?.packageNameAndroid ?? undefined;
|
|
47
57
|
|
|
48
58
|
// Prefer native deep link implementation via OpenIAP module
|
|
49
|
-
if (
|
|
50
|
-
return
|
|
59
|
+
if (nativeAndroidModule?.deepLinkToSubscriptionsAndroid) {
|
|
60
|
+
return nativeAndroidModule.deepLinkToSubscriptionsAndroid({
|
|
51
61
|
skuAndroid: sku,
|
|
52
62
|
packageNameAndroid: packageName,
|
|
53
63
|
});
|
package/src/modules/ios.ts
CHANGED
|
@@ -16,7 +16,7 @@ import type {
|
|
|
16
16
|
SubscriptionStatusIOS,
|
|
17
17
|
} from '../types';
|
|
18
18
|
import type {PurchaseError} from '../utils/errorMapping';
|
|
19
|
-
import {Linking
|
|
19
|
+
import {Linking} from 'react-native';
|
|
20
20
|
|
|
21
21
|
export type TransactionEvent = {
|
|
22
22
|
transaction?: Purchase;
|
|
@@ -178,28 +178,6 @@ export const getReceiptDataIOS: QueryField<'getReceiptDataIOS'> = async () => {
|
|
|
178
178
|
|
|
179
179
|
export const getReceiptIOS = getReceiptDataIOS;
|
|
180
180
|
|
|
181
|
-
/**
|
|
182
|
-
* Retrieves the current storefront information from the iOS App Store.
|
|
183
|
-
*
|
|
184
|
-
* @returns Promise resolving to the storefront country code
|
|
185
|
-
* @throws Error if called on non-iOS platform
|
|
186
|
-
*
|
|
187
|
-
* @example
|
|
188
|
-
* ```typescript
|
|
189
|
-
* const storefront = await getStorefrontIOS();
|
|
190
|
-
* console.log(storefront); // 'US'
|
|
191
|
-
* ```
|
|
192
|
-
*
|
|
193
|
-
* @platform iOS
|
|
194
|
-
*/
|
|
195
|
-
export const getStorefrontIOS: QueryField<'getStorefrontIOS'> = async () => {
|
|
196
|
-
if (Platform.OS !== 'ios') {
|
|
197
|
-
console.warn('getStorefrontIOS: This method is only available on iOS');
|
|
198
|
-
return '';
|
|
199
|
-
}
|
|
200
|
-
return ExpoIapModule.getStorefrontIOS();
|
|
201
|
-
};
|
|
202
|
-
|
|
203
181
|
/**
|
|
204
182
|
* Check if a transaction is verified through StoreKit 2.
|
|
205
183
|
* StoreKit 2 performs local verification of transaction JWS signatures.
|
package/src/types.ts
CHANGED
|
@@ -449,7 +449,12 @@ export interface Query {
|
|
|
449
449
|
getPromotedProductIOS?: Promise<(ProductIOS | null)>;
|
|
450
450
|
/** Get base64-encoded receipt data for validation */
|
|
451
451
|
getReceiptDataIOS?: Promise<(string | null)>;
|
|
452
|
-
/** Get the current
|
|
452
|
+
/** Get the current storefront country code */
|
|
453
|
+
getStorefront: Promise<string>;
|
|
454
|
+
/**
|
|
455
|
+
* Get the current App Store storefront country code
|
|
456
|
+
* @deprecated Use getStorefront
|
|
457
|
+
*/
|
|
453
458
|
getStorefrontIOS: Promise<string>;
|
|
454
459
|
/** Get the transaction JWS (StoreKit 2) */
|
|
455
460
|
getTransactionJwsIOS?: Promise<(string | null)>;
|
|
@@ -680,6 +685,7 @@ export type QueryArgsMap = {
|
|
|
680
685
|
getPendingTransactionsIOS: never;
|
|
681
686
|
getPromotedProductIOS: never;
|
|
682
687
|
getReceiptDataIOS: never;
|
|
688
|
+
getStorefront: never;
|
|
683
689
|
getStorefrontIOS: never;
|
|
684
690
|
getTransactionJwsIOS: QueryGetTransactionJwsIosArgs;
|
|
685
691
|
hasActiveSubscriptions: QueryHasActiveSubscriptionsArgs;
|
package/src/useIAP.ts
CHANGED
|
@@ -37,6 +37,8 @@ import type {
|
|
|
37
37
|
PurchaseInput,
|
|
38
38
|
ReceiptValidationProps,
|
|
39
39
|
ReceiptValidationResult,
|
|
40
|
+
ProductAndroid,
|
|
41
|
+
ProductSubscriptionIOS,
|
|
40
42
|
} from './types';
|
|
41
43
|
import {ErrorCode} from './types';
|
|
42
44
|
import type {PurchaseError} from './utils/errorMapping';
|
|
@@ -159,6 +161,7 @@ export function useIAP(options?: UseIAPOptions): UseIap {
|
|
|
159
161
|
if (!value) {
|
|
160
162
|
return 'in-app';
|
|
161
163
|
}
|
|
164
|
+
|
|
162
165
|
const normalized = value.trim().toLowerCase().replace(/[_-]/g, '');
|
|
163
166
|
return normalized === 'subs' ? 'subs' : 'in-app';
|
|
164
167
|
},
|
|
@@ -191,6 +194,8 @@ export function useIAP(options?: UseIAPOptions): UseIap {
|
|
|
191
194
|
const result = await fetchProducts(request);
|
|
192
195
|
const items = (result ?? []) as (Product | ProductSubscription)[];
|
|
193
196
|
|
|
197
|
+
console.log('Fetched products:', items);
|
|
198
|
+
|
|
194
199
|
if (queryType === 'subs') {
|
|
195
200
|
const subscriptionsResult = items as ProductSubscription[];
|
|
196
201
|
setSubscriptions((prevSubscriptions) =>
|
|
@@ -210,12 +215,40 @@ export function useIAP(options?: UseIAPOptions): UseIap {
|
|
|
210
215
|
),
|
|
211
216
|
);
|
|
212
217
|
} else {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
218
|
+
// For 'all' type, need to properly distinguish between products and subscriptions
|
|
219
|
+
// On Android, check subscriptionOfferDetailsAndroid to determine if it's a real subscription
|
|
220
|
+
const productItems = items.filter((item) => {
|
|
221
|
+
// iOS: check type
|
|
222
|
+
if (Platform.OS === 'ios') {
|
|
223
|
+
return canonicalProductType(item.type as string) === 'in-app';
|
|
224
|
+
}
|
|
225
|
+
// Android: check if it has actual subscription details
|
|
226
|
+
const androidItem = item as ProductAndroid;
|
|
227
|
+
return (
|
|
228
|
+
!androidItem.subscriptionOfferDetailsAndroid ||
|
|
229
|
+
(Array.isArray(androidItem.subscriptionOfferDetailsAndroid) &&
|
|
230
|
+
androidItem.subscriptionOfferDetailsAndroid.length === 0)
|
|
231
|
+
);
|
|
232
|
+
}) as Product[];
|
|
233
|
+
|
|
234
|
+
const subscriptionItems = items.filter((item) => {
|
|
235
|
+
// iOS: check type
|
|
236
|
+
if (Platform.OS === 'ios') {
|
|
237
|
+
return (
|
|
238
|
+
canonicalProductType(
|
|
239
|
+
item.type as ProductSubscriptionIOS['type'],
|
|
240
|
+
) === 'subs'
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
// Android: check if it has actual subscription details
|
|
244
|
+
const androidItem = item as ProductAndroid;
|
|
245
|
+
|
|
246
|
+
return (
|
|
247
|
+
androidItem.subscriptionOfferDetailsAndroid &&
|
|
248
|
+
Array.isArray(androidItem.subscriptionOfferDetailsAndroid) &&
|
|
249
|
+
androidItem.subscriptionOfferDetailsAndroid.length > 0
|
|
250
|
+
);
|
|
251
|
+
}) as ProductSubscription[];
|
|
219
252
|
|
|
220
253
|
setProducts((prevProducts) =>
|
|
221
254
|
mergeWithDuplicateCheck(
|