expo-iap 6.0.1 → 6.0.3
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/AGENTS.md +3 -5
- package/CONTRIBUTING.md +2 -30
- package/android/src/main/java/expo/modules/iap/ExpoIapHelper.kt +10 -5
- package/android/src/main/java/expo/modules/iap/ExpoIapModule.kt +5 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +24 -46
- 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 +2 -1
- package/build/modules/ios.d.ts.map +1 -1
- package/build/modules/ios.js +36 -26
- package/build/modules/ios.js.map +1 -1
- package/build/types.d.ts +6 -0
- package/build/types.d.ts.map +1 -1
- package/build/types.js.map +1 -1
- package/build/useIAP.d.ts +5 -4
- package/build/useIAP.d.ts.map +1 -1
- package/build/useIAP.js +128 -170
- package/build/useIAP.js.map +1 -1
- package/build/utils/errorMapping.d.ts +12 -15
- package/build/utils/errorMapping.d.ts.map +1 -1
- package/build/utils/errorMapping.js +113 -298
- package/build/utils/errorMapping.js.map +1 -1
- package/build/utils/nativeError.d.ts +20 -0
- package/build/utils/nativeError.d.ts.map +1 -0
- package/build/utils/nativeError.js +138 -0
- package/build/utils/nativeError.js.map +1 -0
- package/build/utils/packageName.d.ts +3 -0
- package/build/utils/packageName.d.ts.map +1 -0
- package/build/utils/packageName.js +3 -0
- package/build/utils/packageName.js.map +1 -0
- package/ios/ExpoIapHelper.swift +26 -0
- package/ios/ExpoIapModule.swift +252 -273
- package/openiap-versions.json +3 -3
- package/package.json +1 -1
- package/src/index.ts +61 -60
- package/src/modules/android.ts +9 -2
- package/src/modules/ios.ts +70 -29
- package/src/types.ts +7 -0
- package/src/useIAP.ts +158 -210
- package/src/utils/errorMapping.ts +136 -370
- package/src/utils/nativeError.ts +187 -0
- package/src/utils/packageName.ts +2 -0
package/AGENTS.md
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Commit Message Convention
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
- Subject must be imperative, lowercase, without a trailing period, and roughly 50 characters
|
|
9
|
-
- Wrap commit body lines near 72 characters and include footers such as `BREAKING CHANGE:` or `Closes #123` when needed
|
|
5
|
+
Follow the monorepo
|
|
6
|
+
[Git Commit Message Format](../../knowledge/internal/06-git-deployment.md#git-commit-message-format)
|
|
7
|
+
with the `expo` scope, e.g. `fix(expo): resolve purchase crash`.
|
|
10
8
|
|
|
11
9
|
## Tooling & Package Management
|
|
12
10
|
|
package/CONTRIBUTING.md
CHANGED
|
@@ -363,36 +363,8 @@ bun run lint:prettier
|
|
|
363
363
|
|
|
364
364
|
### Commit Messages
|
|
365
365
|
|
|
366
|
-
Follow
|
|
367
|
-
|
|
368
|
-
```text
|
|
369
|
-
type(scope): subject
|
|
370
|
-
|
|
371
|
-
body
|
|
372
|
-
|
|
373
|
-
footer
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
Types:
|
|
377
|
-
|
|
378
|
-
- `feat`: new feature
|
|
379
|
-
- `fix`: bug fix
|
|
380
|
-
- `docs`: documentation changes
|
|
381
|
-
- `style`: code style changes (formatting, etc.)
|
|
382
|
-
- `refactor`: code refactoring
|
|
383
|
-
- `test`: test additions or modifications
|
|
384
|
-
- `chore`: maintenance tasks
|
|
385
|
-
|
|
386
|
-
Example:
|
|
387
|
-
|
|
388
|
-
```text
|
|
389
|
-
feat(ios): add getStorefrontIos function
|
|
390
|
-
|
|
391
|
-
Implements iOS-specific storefront retrieval using StoreKit.
|
|
392
|
-
Follows platform-specific naming convention.
|
|
393
|
-
|
|
394
|
-
Closes #123
|
|
395
|
-
```
|
|
366
|
+
Follow the monorepo's [Git Commit Message Format](https://github.com/hyodotdev/openiap/blob/main/knowledge/internal/06-git-deployment.md#git-commit-message-format),
|
|
367
|
+
for example `feat(expo): add getAppTransactionIOS`.
|
|
396
368
|
|
|
397
369
|
### Pull Request Process
|
|
398
370
|
|
|
@@ -45,6 +45,15 @@ object ExpoIapHelper {
|
|
|
45
45
|
|
|
46
46
|
internal fun serializeErrorEnvelope(payload: Map<String, Any?>): String = ERROR_ENVELOPE_PREFIX + JSONObject(payload).toString()
|
|
47
47
|
|
|
48
|
+
/** Rejects with the canonical error envelope that the JS bridge parses. */
|
|
49
|
+
internal fun rejectWithErrorEnvelope(
|
|
50
|
+
promise: Promise,
|
|
51
|
+
error: Exception,
|
|
52
|
+
) {
|
|
53
|
+
val openIapError = error as? OpenIapError ?: OpenIapError.ServiceUnavailable(error.message)
|
|
54
|
+
promise.reject(openIapError.code, serializeErrorEnvelope(serializeOpenIapError(openIapError)), null)
|
|
55
|
+
}
|
|
56
|
+
|
|
48
57
|
fun emitOrQueue(
|
|
49
58
|
module: Module,
|
|
50
59
|
scope: CoroutineScope,
|
|
@@ -282,7 +291,6 @@ object ExpoIapHelper {
|
|
|
282
291
|
eventName: String,
|
|
283
292
|
payload: Map<String, Any?>,
|
|
284
293
|
eventPurchaseError: String,
|
|
285
|
-
fallbackErrorCode: String,
|
|
286
294
|
fallbackErrorPrefix: String,
|
|
287
295
|
logTag: String,
|
|
288
296
|
) {
|
|
@@ -292,7 +300,7 @@ object ExpoIapHelper {
|
|
|
292
300
|
ExpoIapLog.failure("buffer/send $logTag", error)
|
|
293
301
|
val errorPayload =
|
|
294
302
|
mapOf(
|
|
295
|
-
"code" to
|
|
303
|
+
"code" to OpenIapError.UnknownError.CODE,
|
|
296
304
|
"message" to "$fallbackErrorPrefix: ${error.message}",
|
|
297
305
|
)
|
|
298
306
|
runCatching {
|
|
@@ -397,7 +405,6 @@ object ExpoIapHelper {
|
|
|
397
405
|
eventUserChoiceBilling,
|
|
398
406
|
details.toJson(),
|
|
399
407
|
eventPurchaseError,
|
|
400
|
-
"alternative-billing-not-available",
|
|
401
408
|
"Failed to process user choice billing",
|
|
402
409
|
"USER_CHOICE_BILLING",
|
|
403
410
|
)
|
|
@@ -415,7 +422,6 @@ object ExpoIapHelper {
|
|
|
415
422
|
eventDeveloperProvidedBilling,
|
|
416
423
|
details.toJson(),
|
|
417
424
|
eventPurchaseError,
|
|
418
|
-
"developer-billing-error",
|
|
419
425
|
"Failed to process developer provided billing",
|
|
420
426
|
"DEVELOPER_PROVIDED_BILLING",
|
|
421
427
|
)
|
|
@@ -433,7 +439,6 @@ object ExpoIapHelper {
|
|
|
433
439
|
eventSubscriptionBillingIssue,
|
|
434
440
|
purchase.toJson(),
|
|
435
441
|
eventPurchaseError,
|
|
436
|
-
"subscription-billing-issue-error",
|
|
437
442
|
"Failed to process subscription billing issue",
|
|
438
443
|
"SUBSCRIPTION_BILLING_ISSUE",
|
|
439
444
|
)
|
|
@@ -25,6 +25,7 @@ import dev.hyo.openiap.VerifyPurchaseHorizonOptions
|
|
|
25
25
|
import dev.hyo.openiap.VerifyPurchaseProps
|
|
26
26
|
import dev.hyo.openiap.VerifyPurchaseWithProviderProps
|
|
27
27
|
import dev.hyo.openiap.helpers.OpenIapFirstPurchaseNotice
|
|
28
|
+
import dev.hyo.openiap.helpers.finishPurchaseToken
|
|
28
29
|
import dev.hyo.openiap.store.OpenIapStore
|
|
29
30
|
import expo.modules.kotlin.Promise
|
|
30
31
|
import expo.modules.kotlin.exception.Exceptions
|
|
@@ -529,13 +530,13 @@ class ExpoIapModule : Module() {
|
|
|
529
530
|
ExpoIapLog.payload("acknowledgePurchaseAndroid", mapOf("token" to token))
|
|
530
531
|
scope.launch {
|
|
531
532
|
try {
|
|
532
|
-
openIap.
|
|
533
|
+
openIap.finishPurchaseToken(token, isConsumable = false)
|
|
533
534
|
val response = mapOf("responseCode" to 0)
|
|
534
535
|
ExpoIapLog.result("acknowledgePurchaseAndroid", response)
|
|
535
536
|
promise.resolve(response)
|
|
536
537
|
} catch (e: Exception) {
|
|
537
538
|
ExpoIapLog.failure("acknowledgePurchaseAndroid", e)
|
|
538
|
-
|
|
539
|
+
ExpoIapHelper.rejectWithErrorEnvelope(promise, e)
|
|
539
540
|
}
|
|
540
541
|
}
|
|
541
542
|
}
|
|
@@ -544,7 +545,7 @@ class ExpoIapModule : Module() {
|
|
|
544
545
|
ExpoIapLog.payload("consumePurchaseAndroid", mapOf("token" to token))
|
|
545
546
|
scope.launch {
|
|
546
547
|
try {
|
|
547
|
-
openIap.
|
|
548
|
+
openIap.finishPurchaseToken(token, isConsumable = true)
|
|
548
549
|
val response = mapOf("responseCode" to 0, "purchaseToken" to token)
|
|
549
550
|
ExpoIapLog.result(
|
|
550
551
|
"consumePurchaseAndroid",
|
|
@@ -553,7 +554,7 @@ class ExpoIapModule : Module() {
|
|
|
553
554
|
promise.resolve(response)
|
|
554
555
|
} catch (e: Exception) {
|
|
555
556
|
ExpoIapLog.failure("consumePurchaseAndroid", e)
|
|
556
|
-
|
|
557
|
+
ExpoIapHelper.rejectWithErrorEnvelope(promise, e)
|
|
557
558
|
}
|
|
558
559
|
}
|
|
559
560
|
}
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAGV,sCAAsC,EAEtC,aAAa,EAEb,OAAO,EACP,gBAAgB,EAEhB,QAAQ,EAER,8BAA8B,EAC9B,UAAU,EAOV,wBAAwB,EACzB,MAAM,SAAS,CAAC;AAEjB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -10,7 +10,8 @@ import { showFirstPurchaseNotice } from './utils/firstPurchaseNotice';
|
|
|
10
10
|
import { restorePurchasesNative } from './utils/restorePurchases';
|
|
11
11
|
import { decodeAndroidPurchases, decodeApplePurchases, } from './utils/availablePurchases';
|
|
12
12
|
import { ErrorCode, resolveStoreId } from './types';
|
|
13
|
-
import { createPurchaseError,
|
|
13
|
+
import { createPurchaseError, normalizeErrorCodeFromNative, } from './utils/errorMapping';
|
|
14
|
+
import { createPurchaseErrorFromNativeException, invokeNativeWithPurchaseError, } from './utils/nativeError';
|
|
14
15
|
export * from './types';
|
|
15
16
|
export * from './modules/android';
|
|
16
17
|
export * from './modules/ios';
|
|
@@ -33,6 +34,8 @@ export var OpenIapEvent;
|
|
|
33
34
|
const isStorePlatform = () => Platform.OS === 'ios' || Platform.OS === 'android';
|
|
34
35
|
const isStoreRuntime = () => Platform.OS === 'ios' || isAndroidStoreRuntime();
|
|
35
36
|
const unsupportedPlatformError = () => new Error(`Unsupported platform: ${Platform.OS}`);
|
|
37
|
+
// Platform tag for PurchaseErrors built from native rejections.
|
|
38
|
+
const nativePlatform = () => Platform.OS === 'ios' ? 'ios' : 'android';
|
|
36
39
|
// Listener calls go to the raw native module (see getNativeModule), resolved
|
|
37
40
|
// lazily so importing this module doesn't throw on unsupported platforms.
|
|
38
41
|
export const emitter = {
|
|
@@ -185,8 +188,9 @@ export const purchaseUpdatedListener = (listener, options) => {
|
|
|
185
188
|
};
|
|
186
189
|
};
|
|
187
190
|
export const purchaseErrorListener = (listener) => {
|
|
191
|
+
// Native events may carry codes outside ErrorCode; deliver canonical codes.
|
|
188
192
|
const wrappedListener = (error) => {
|
|
189
|
-
listener(error);
|
|
193
|
+
listener({ ...error, code: normalizeErrorCodeFromNative(error.code) });
|
|
190
194
|
};
|
|
191
195
|
const emitterSubscription = emitter.addListener(OpenIapEvent.PurchaseError, wrappedListener);
|
|
192
196
|
return emitterSubscription;
|
|
@@ -371,7 +375,7 @@ export const subscriptionBillingIssueListener = (listener) => {
|
|
|
371
375
|
* @see {@link https://openiap.dev/docs/apis/init-connection}
|
|
372
376
|
*/
|
|
373
377
|
export const initConnection = async (config) => {
|
|
374
|
-
const result = await ExpoIapModule.initConnection(config ?? null);
|
|
378
|
+
const result = await invokeNativeWithPurchaseError(() => ExpoIapModule.initConnection(config ?? null), nativePlatform());
|
|
375
379
|
if (result === true &&
|
|
376
380
|
Platform.OS === 'ios' &&
|
|
377
381
|
nonDedupingPurchaseUpdatedListenerCountIOS > 0) {
|
|
@@ -385,38 +389,12 @@ export const initConnection = async (config) => {
|
|
|
385
389
|
* @see {@link https://openiap.dev/docs/apis/end-connection}
|
|
386
390
|
*/
|
|
387
391
|
export const endConnection = async () => {
|
|
388
|
-
const result = await ExpoIapModule.endConnection();
|
|
392
|
+
const result = await invokeNativeWithPurchaseError(() => ExpoIapModule.endConnection(), nativePlatform());
|
|
389
393
|
if (result === true && Platform.OS === 'ios') {
|
|
390
394
|
resetPurchaseUpdatedDedupeHistoryIOS();
|
|
391
395
|
}
|
|
392
396
|
return result;
|
|
393
397
|
};
|
|
394
|
-
const invokeNativeWithPurchaseError = async (operation, platform, fallback) => {
|
|
395
|
-
try {
|
|
396
|
-
return await operation();
|
|
397
|
-
}
|
|
398
|
-
catch (error) {
|
|
399
|
-
const nativeError = typeof error === 'object' && error !== null
|
|
400
|
-
? error
|
|
401
|
-
: undefined;
|
|
402
|
-
const nativeMessage = typeof nativeError?.message === 'string'
|
|
403
|
-
? nativeError.message
|
|
404
|
-
: typeof error === 'string'
|
|
405
|
-
? error
|
|
406
|
-
: '';
|
|
407
|
-
const hasCanonicalFields = nativeMessage.includes(OPENIAP_ERROR_ENVELOPE_PREFIX) ||
|
|
408
|
-
nativeError?.code !== undefined ||
|
|
409
|
-
nativeError?.responseCode !== undefined ||
|
|
410
|
-
nativeError?.debugMessage !== undefined ||
|
|
411
|
-
nativeError?.productId !== undefined ||
|
|
412
|
-
nativeError?.productIds !== undefined;
|
|
413
|
-
// Preserve the identity of unrelated JavaScript errors (including adapter
|
|
414
|
-
// or test errors) while normalizing native OpenIAP rejections.
|
|
415
|
-
if (!hasCanonicalFields)
|
|
416
|
-
throw error;
|
|
417
|
-
throw createPurchaseErrorFromNativeException(error, platform, fallback);
|
|
418
|
-
}
|
|
419
|
-
};
|
|
420
398
|
/**
|
|
421
399
|
* Retrieve products or subscriptions from the store by SKU.
|
|
422
400
|
*
|
|
@@ -525,10 +503,10 @@ export const getAvailablePurchases = async (options) => {
|
|
|
525
503
|
}
|
|
526
504
|
let purchases;
|
|
527
505
|
if (Platform.OS === 'ios') {
|
|
528
|
-
purchases = (await ExpoIapModule.getAvailableItems(normalizedOptions.alsoPublishToEventListenerIOS, normalizedOptions.onlyIncludeActiveItemsIOS));
|
|
506
|
+
purchases = (await invokeNativeWithPurchaseError(() => ExpoIapModule.getAvailableItems(normalizedOptions.alsoPublishToEventListenerIOS, normalizedOptions.onlyIncludeActiveItemsIOS), 'ios'));
|
|
529
507
|
}
|
|
530
508
|
else if (Platform.OS === 'android') {
|
|
531
|
-
purchases = (await ExpoIapModule.getAvailableItems(normalizedOptions));
|
|
509
|
+
purchases = (await invokeNativeWithPurchaseError(() => ExpoIapModule.getAvailableItems(normalizedOptions), 'android'));
|
|
532
510
|
}
|
|
533
511
|
else {
|
|
534
512
|
throw unsupportedPlatformError();
|
|
@@ -567,7 +545,7 @@ export const getActiveSubscriptions = async (subscriptionIds) => {
|
|
|
567
545
|
if (!isStoreRuntime()) {
|
|
568
546
|
throw unsupportedPlatformError();
|
|
569
547
|
}
|
|
570
|
-
const result = await ExpoIapModule.getActiveSubscriptions(subscriptionIds ?? null);
|
|
548
|
+
const result = await invokeNativeWithPurchaseError(() => ExpoIapModule.getActiveSubscriptions(subscriptionIds ?? null), nativePlatform());
|
|
571
549
|
return (result ?? []);
|
|
572
550
|
};
|
|
573
551
|
/**
|
|
@@ -591,7 +569,7 @@ export const hasActiveSubscriptions = async (subscriptionIds) => {
|
|
|
591
569
|
if (!isStoreRuntime()) {
|
|
592
570
|
throw unsupportedPlatformError();
|
|
593
571
|
}
|
|
594
|
-
return !!(await ExpoIapModule.hasActiveSubscriptions(subscriptionIds ?? null));
|
|
572
|
+
return !!(await invokeNativeWithPurchaseError(() => ExpoIapModule.hasActiveSubscriptions(subscriptionIds ?? null), nativePlatform()));
|
|
595
573
|
};
|
|
596
574
|
/**
|
|
597
575
|
* Return the user's storefront country code.
|
|
@@ -605,7 +583,7 @@ export const getStorefront = async () => {
|
|
|
605
583
|
message: `Storefront lookup is not supported on ${Platform.OS}.`,
|
|
606
584
|
});
|
|
607
585
|
}
|
|
608
|
-
const platform =
|
|
586
|
+
const platform = nativePlatform();
|
|
609
587
|
if (typeof ExpoIapModule.getStorefront !== 'function') {
|
|
610
588
|
throw createPurchaseError({
|
|
611
589
|
code: ErrorCode.FeatureNotSupported,
|
|
@@ -673,7 +651,7 @@ export const verifyAppOwnership = async (options) => {
|
|
|
673
651
|
: 'unknown',
|
|
674
652
|
};
|
|
675
653
|
}
|
|
676
|
-
return invokeNativeWithPurchaseError(() => ExpoIapModule.verifyAppOwnership(options ?? {}),
|
|
654
|
+
return invokeNativeWithPurchaseError(() => ExpoIapModule.verifyAppOwnership(options ?? {}), nativePlatform(), {
|
|
677
655
|
code: ErrorCode.ServiceError,
|
|
678
656
|
});
|
|
679
657
|
};
|
|
@@ -858,9 +836,10 @@ export const requestPurchase = async (args) => {
|
|
|
858
836
|
export const finishTransaction = async ({ purchase, isConsumable, }) => {
|
|
859
837
|
// The schema allows explicit null; the native boolean cannot take it.
|
|
860
838
|
const consumable = isConsumable ?? false;
|
|
839
|
+
const platform = nativePlatform();
|
|
861
840
|
if (Platform.OS === 'ios' ||
|
|
862
841
|
(isAndroidStoreRuntime() && purchase.store === 'unknown')) {
|
|
863
|
-
await ExpoIapModule.finishTransaction(purchase, consumable);
|
|
842
|
+
await invokeNativeWithPurchaseError(() => ExpoIapModule.finishTransaction(purchase, consumable), platform, { productId: purchase.productId });
|
|
864
843
|
}
|
|
865
844
|
else if (isAndroidStoreRuntime()) {
|
|
866
845
|
const token = purchase.purchaseToken ?? undefined;
|
|
@@ -872,12 +851,10 @@ export const finishTransaction = async ({ purchase, isConsumable, }) => {
|
|
|
872
851
|
platform: 'android',
|
|
873
852
|
});
|
|
874
853
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
await ExpoIapModule.acknowledgePurchaseAndroid(token);
|
|
880
|
-
}
|
|
854
|
+
// Native rejects when the store refuses the token, so a failure cannot pass as finished.
|
|
855
|
+
await invokeNativeWithPurchaseError(() => consumable
|
|
856
|
+
? ExpoIapModule.consumePurchaseAndroid(token)
|
|
857
|
+
: ExpoIapModule.acknowledgePurchaseAndroid(token), 'android', { productId: purchase.productId });
|
|
881
858
|
}
|
|
882
859
|
else {
|
|
883
860
|
throw unsupportedPlatformError();
|
|
@@ -949,7 +926,7 @@ export const openRedeemOfferCode = async () => {
|
|
|
949
926
|
if (Platform.OS !== 'ios' && !isAndroidStoreRuntime()) {
|
|
950
927
|
throw unsupportedPlatformError();
|
|
951
928
|
}
|
|
952
|
-
return invokeNativeWithPurchaseError(() => ExpoIapModule.openRedeemOfferCode(),
|
|
929
|
+
return invokeNativeWithPurchaseError(() => ExpoIapModule.openRedeemOfferCode(), nativePlatform(), { code: ErrorCode.PurchaseError, message: 'Failed to redeem offer code.' });
|
|
953
930
|
};
|
|
954
931
|
/**
|
|
955
932
|
* Verify purchase with the configured providers.
|
|
@@ -963,7 +940,8 @@ export const verifyPurchase = async (options) => {
|
|
|
963
940
|
if (!isStorePlatform()) {
|
|
964
941
|
throw unsupportedPlatformError();
|
|
965
942
|
}
|
|
966
|
-
|
|
943
|
+
// The native result is already the flat union member, with `__typename`.
|
|
944
|
+
return invokeNativeWithPurchaseError(() => ExpoIapModule.verifyPurchase(options), nativePlatform());
|
|
967
945
|
};
|
|
968
946
|
/**
|
|
969
947
|
* Verify purchase with a specific provider (e.g., IAPKit).
|
|
@@ -1021,7 +999,7 @@ export const verifyPurchaseWithProvider = async (options) => {
|
|
|
1021
999
|
'Or provide apiKey directly in verifyPurchaseWithProvider options.');
|
|
1022
1000
|
}
|
|
1023
1001
|
}
|
|
1024
|
-
const result = await ExpoIapModule.verifyPurchaseWithProvider(resolvedOptions);
|
|
1002
|
+
const result = await invokeNativeWithPurchaseError(() => ExpoIapModule.verifyPurchaseWithProvider(resolvedOptions), nativePlatform());
|
|
1025
1003
|
if (result.iapkit == null) {
|
|
1026
1004
|
return result;
|
|
1027
1005
|
}
|