expo-iap 2.8.2 → 2.8.3-rc.2
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/CHANGELOG.md +0 -10
- package/CLAUDE.md +11 -0
- package/CONTRIBUTING.md +3 -4
- package/build/helpers/subscription.d.ts.map +1 -1
- package/build/helpers/subscription.js +3 -6
- package/build/helpers/subscription.js.map +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -1
- package/build/index.js.map +1 -1
- package/build/modules/android.d.ts.map +1 -1
- package/build/modules/android.js.map +1 -1
- package/build/modules/ios.d.ts.map +1 -1
- package/build/modules/ios.js.map +1 -1
- package/build/types/ExpoIapAndroid.types.d.ts +2 -2
- package/build/types/ExpoIapAndroid.types.d.ts.map +1 -1
- package/build/types/ExpoIapAndroid.types.js.map +1 -1
- package/build/types/ExpoIapIOS.types.d.ts +3 -3
- package/build/types/ExpoIapIOS.types.d.ts.map +1 -1
- package/build/types/ExpoIapIOS.types.js.map +1 -1
- package/build/useIAP.d.ts.map +1 -1
- package/build/useIAP.js.map +1 -1
- package/coverage/clover.xml +601 -0
- package/coverage/coverage-final.json +9 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +176 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/ExpoIap.types.ts.html +1243 -0
- package/coverage/lcov-report/src/helpers/index.html +116 -0
- package/coverage/lcov-report/src/helpers/subscription.ts.html +430 -0
- package/coverage/lcov-report/src/index.html +146 -0
- package/coverage/lcov-report/src/index.ts.html +2227 -0
- package/coverage/lcov-report/src/modules/android.ts.html +469 -0
- package/coverage/lcov-report/src/modules/index.html +131 -0
- package/coverage/lcov-report/src/modules/ios.ts.html +1411 -0
- package/coverage/lcov-report/src/types/ExpoIapAndroid.types.ts.html +487 -0
- package/coverage/lcov-report/src/types/index.html +116 -0
- package/coverage/lcov-report/src/useIap.ts.html +1483 -0
- package/coverage/lcov-report/src/utils/errorMapping.ts.html +349 -0
- package/coverage/lcov-report/src/utils/index.html +116 -0
- package/coverage/lcov.info +1115 -0
- package/ios/ExpoIap.podspec +6 -1
- package/ios/expoiap.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/expoiap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/jest.config.js +14 -17
- package/package.json +1 -1
- package/plugin/build/withIAP.js +16 -3
- package/plugin/src/withIAP.ts +22 -3
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/src/helpers/subscription.ts +21 -28
- package/src/index.ts +10 -5
- package/src/modules/android.ts +7 -7
- package/src/modules/ios.ts +7 -2
- package/src/types/ExpoIapAndroid.types.ts +3 -4
- package/src/types/ExpoIapIOS.types.ts +4 -3
- package/src/useIAP.ts +9 -3
package/ios/ExpoIap.podspec
CHANGED
|
@@ -10,7 +10,12 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package['license']
|
|
11
11
|
s.author = package['author']
|
|
12
12
|
s.homepage = package['homepage']
|
|
13
|
-
|
|
13
|
+
# WARNING: DO NOT MODIFY iOS platform version from 13.4
|
|
14
|
+
# Changing this to 15.0 causes expo prebuild to exclude the module in older Expo versions (known bug)
|
|
15
|
+
# See: https://github.com/hyochan/expo-iap/issues/168
|
|
16
|
+
# Even though the code requires iOS 15.0+ for StoreKit 2, keep this at 13.4 for compatibility across all Expo versions
|
|
17
|
+
# The actual iOS 15.0+ requirement is enforced at build time
|
|
18
|
+
s.platforms = { :ios => '13.4', :tvos => '15.0' }
|
|
14
19
|
s.swift_version = '5.4'
|
|
15
20
|
s.source = { git: 'https://github.com/hyochan/expo-iap' }
|
|
16
21
|
s.static_framework = true
|
package/jest.config.js
CHANGED
|
@@ -4,21 +4,18 @@ module.exports = {
|
|
|
4
4
|
roots: ['<rootDir>/src'],
|
|
5
5
|
testMatch: [
|
|
6
6
|
'**/__tests__/**/*.+(ts|tsx|js)',
|
|
7
|
-
'**/?(*.)+(spec|test).+(ts|tsx|js)'
|
|
7
|
+
'**/?(*.)+(spec|test).+(ts|tsx|js)'
|
|
8
8
|
],
|
|
9
9
|
transform: {
|
|
10
|
-
'^.+\\.(ts|tsx)$': [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
],
|
|
10
|
+
'^.+\\.(ts|tsx)$': ['ts-jest', {
|
|
11
|
+
tsconfig: {
|
|
12
|
+
jsx: 'react',
|
|
13
|
+
esModuleInterop: true,
|
|
14
|
+
allowSyntheticDefaultImports: true,
|
|
15
|
+
moduleResolution: 'node',
|
|
16
|
+
skipLibCheck: true,
|
|
17
|
+
}
|
|
18
|
+
}]
|
|
22
19
|
},
|
|
23
20
|
moduleNameMapper: {
|
|
24
21
|
'^react-native$': '<rootDir>/src/__mocks__/react-native.js',
|
|
@@ -37,7 +34,7 @@ module.exports = {
|
|
|
37
34
|
branches: 15,
|
|
38
35
|
functions: 15,
|
|
39
36
|
lines: 15,
|
|
40
|
-
statements: 15
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
};
|
|
37
|
+
statements: 15
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
package/package.json
CHANGED
package/plugin/build/withIAP.js
CHANGED
|
@@ -36,7 +36,18 @@ const modifyAppBuildGradle = (gradle) => {
|
|
|
36
36
|
}
|
|
37
37
|
return modified;
|
|
38
38
|
};
|
|
39
|
-
const
|
|
39
|
+
const withIapIOS = (config) => {
|
|
40
|
+
// Add In-App Purchase capability to entitlements
|
|
41
|
+
config = (0, config_plugins_1.withEntitlementsPlist)(config, (config) => {
|
|
42
|
+
config.modResults['com.apple.developer.in-app-payments'] = ['Default'];
|
|
43
|
+
if (!hasLoggedPluginExecution) {
|
|
44
|
+
console.log('✅ Added In-App Purchase capability to iOS entitlements');
|
|
45
|
+
}
|
|
46
|
+
return config;
|
|
47
|
+
});
|
|
48
|
+
return config;
|
|
49
|
+
};
|
|
50
|
+
const withIapAndroid = (config) => {
|
|
40
51
|
// Add IAP dependencies to app build.gradle
|
|
41
52
|
config = (0, config_plugins_1.withAppBuildGradle)(config, (config) => {
|
|
42
53
|
config.modResults.contents = modifyAppBuildGradle(config.modResults.contents);
|
|
@@ -67,10 +78,12 @@ const withIAPAndroid = (config) => {
|
|
|
67
78
|
};
|
|
68
79
|
const withIAP = (config, _props) => {
|
|
69
80
|
try {
|
|
70
|
-
|
|
81
|
+
// Apply both iOS and Android configurations
|
|
82
|
+
config = withIapIOS(config);
|
|
83
|
+
config = withIapAndroid(config);
|
|
71
84
|
// Set flag after first execution to prevent duplicate logs
|
|
72
85
|
hasLoggedPluginExecution = true;
|
|
73
|
-
return
|
|
86
|
+
return config;
|
|
74
87
|
}
|
|
75
88
|
catch (error) {
|
|
76
89
|
config_plugins_1.WarningAggregator.addWarningAndroid('expo-iap', `expo-iap plugin encountered an error: ${error}`);
|
package/plugin/src/withIAP.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
WarningAggregator,
|
|
5
5
|
withAndroidManifest,
|
|
6
6
|
withAppBuildGradle,
|
|
7
|
+
withEntitlementsPlist,
|
|
7
8
|
} from 'expo/config-plugins';
|
|
8
9
|
|
|
9
10
|
const pkg = require('../../package.json');
|
|
@@ -56,7 +57,22 @@ const modifyAppBuildGradle = (gradle: string): string => {
|
|
|
56
57
|
return modified;
|
|
57
58
|
};
|
|
58
59
|
|
|
59
|
-
const
|
|
60
|
+
const withIapIOS: ConfigPlugin = (config) => {
|
|
61
|
+
// Add In-App Purchase capability to entitlements
|
|
62
|
+
config = withEntitlementsPlist(config, (config) => {
|
|
63
|
+
config.modResults['com.apple.developer.in-app-payments'] = ['Default'];
|
|
64
|
+
|
|
65
|
+
if (!hasLoggedPluginExecution) {
|
|
66
|
+
console.log('✅ Added In-App Purchase capability to iOS entitlements');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return config;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return config;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const withIapAndroid: ConfigPlugin = (config) => {
|
|
60
76
|
// Add IAP dependencies to app build.gradle
|
|
61
77
|
config = withAppBuildGradle(config, (config) => {
|
|
62
78
|
config.modResults.contents = modifyAppBuildGradle(
|
|
@@ -100,10 +116,13 @@ const withIAPAndroid: ConfigPlugin = (config) => {
|
|
|
100
116
|
|
|
101
117
|
const withIAP: ConfigPlugin = (config, _props) => {
|
|
102
118
|
try {
|
|
103
|
-
|
|
119
|
+
// Apply both iOS and Android configurations
|
|
120
|
+
config = withIapIOS(config);
|
|
121
|
+
config = withIapAndroid(config);
|
|
122
|
+
|
|
104
123
|
// Set flag after first execution to prevent duplicate logs
|
|
105
124
|
hasLoggedPluginExecution = true;
|
|
106
|
-
return
|
|
125
|
+
return config;
|
|
107
126
|
} catch (error) {
|
|
108
127
|
WarningAggregator.addWarningAndroid(
|
|
109
128
|
'expo-iap',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/
|
|
1
|
+
{"root":["./src/withiap.ts"],"version":"5.8.3"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {Platform} from 'react-native';
|
|
2
|
-
import {getAvailablePurchases} from '../index';
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import { getAvailablePurchases } from '../index';
|
|
3
3
|
|
|
4
4
|
export interface ActiveSubscription {
|
|
5
5
|
productId: string;
|
|
@@ -17,13 +17,13 @@ export interface ActiveSubscription {
|
|
|
17
17
|
* @returns Promise<ActiveSubscription[]> array of active subscriptions with details
|
|
18
18
|
*/
|
|
19
19
|
export const getActiveSubscriptions = async (
|
|
20
|
-
subscriptionIds?: string[]
|
|
20
|
+
subscriptionIds?: string[]
|
|
21
21
|
): Promise<ActiveSubscription[]> => {
|
|
22
22
|
try {
|
|
23
23
|
const purchases = await getAvailablePurchases();
|
|
24
24
|
const currentTime = Date.now();
|
|
25
25
|
const activeSubscriptions: ActiveSubscription[] = [];
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
// Filter purchases to find active subscriptions
|
|
28
28
|
const filteredPurchases = purchases.filter((purchase) => {
|
|
29
29
|
// If specific IDs provided, filter by them
|
|
@@ -32,17 +32,17 @@ export const getActiveSubscriptions = async (
|
|
|
32
32
|
return false;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
// Check if this purchase has subscription-specific fields
|
|
37
|
-
const hasSubscriptionFields =
|
|
37
|
+
const hasSubscriptionFields =
|
|
38
38
|
('expirationDateIOS' in purchase && purchase.expirationDateIOS) ||
|
|
39
|
-
'autoRenewingAndroid' in purchase ||
|
|
39
|
+
('autoRenewingAndroid' in purchase) ||
|
|
40
40
|
('environmentIOS' in purchase && purchase.environmentIOS === 'Sandbox');
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
if (!hasSubscriptionFields) {
|
|
43
43
|
return false;
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
// Check if it's actually active
|
|
47
47
|
if (Platform.OS === 'ios') {
|
|
48
48
|
if ('expirationDateIOS' in purchase && purchase.expirationDateIOS) {
|
|
@@ -53,15 +53,8 @@ export const getActiveSubscriptions = async (
|
|
|
53
53
|
if ('environmentIOS' in purchase && purchase.environmentIOS) {
|
|
54
54
|
const dayInMs = 24 * 60 * 60 * 1000;
|
|
55
55
|
// If no expiration date, consider active if transaction is recent (within 24 hours for Sandbox)
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
!purchase.expirationDateIOS
|
|
59
|
-
) {
|
|
60
|
-
if (
|
|
61
|
-
purchase.environmentIOS === 'Sandbox' &&
|
|
62
|
-
purchase.transactionDate &&
|
|
63
|
-
currentTime - purchase.transactionDate < dayInMs
|
|
64
|
-
) {
|
|
56
|
+
if (!('expirationDateIOS' in purchase) || !purchase.expirationDateIOS) {
|
|
57
|
+
if (purchase.environmentIOS === 'Sandbox' && purchase.transactionDate && (currentTime - purchase.transactionDate) < dayInMs) {
|
|
65
58
|
return true;
|
|
66
59
|
}
|
|
67
60
|
}
|
|
@@ -70,31 +63,31 @@ export const getActiveSubscriptions = async (
|
|
|
70
63
|
// For Android, if it's in the purchases list, it's active
|
|
71
64
|
return true;
|
|
72
65
|
}
|
|
73
|
-
|
|
66
|
+
|
|
74
67
|
return false;
|
|
75
68
|
});
|
|
76
|
-
|
|
69
|
+
|
|
77
70
|
// Convert to ActiveSubscription format
|
|
78
71
|
for (const purchase of filteredPurchases) {
|
|
79
72
|
const subscription: ActiveSubscription = {
|
|
80
73
|
productId: purchase.productId,
|
|
81
74
|
isActive: true,
|
|
82
75
|
};
|
|
83
|
-
|
|
76
|
+
|
|
84
77
|
// Add platform-specific details
|
|
85
78
|
if (Platform.OS === 'ios') {
|
|
86
79
|
if ('expirationDateIOS' in purchase && purchase.expirationDateIOS) {
|
|
87
80
|
const expirationDate = new Date(purchase.expirationDateIOS);
|
|
88
81
|
subscription.expirationDateIOS = expirationDate;
|
|
89
|
-
|
|
82
|
+
|
|
90
83
|
// Calculate days until expiration (round to nearest day)
|
|
91
84
|
const daysUntilExpiration = Math.round(
|
|
92
|
-
(purchase.expirationDateIOS - currentTime) / (1000 * 60 * 60 * 24)
|
|
85
|
+
(purchase.expirationDateIOS - currentTime) / (1000 * 60 * 60 * 24)
|
|
93
86
|
);
|
|
94
87
|
subscription.daysUntilExpirationIOS = daysUntilExpiration;
|
|
95
88
|
subscription.willExpireSoon = daysUntilExpiration <= 7;
|
|
96
89
|
}
|
|
97
|
-
|
|
90
|
+
|
|
98
91
|
if ('environmentIOS' in purchase) {
|
|
99
92
|
subscription.environmentIOS = purchase.environmentIOS;
|
|
100
93
|
}
|
|
@@ -105,10 +98,10 @@ export const getActiveSubscriptions = async (
|
|
|
105
98
|
subscription.willExpireSoon = !purchase.autoRenewingAndroid;
|
|
106
99
|
}
|
|
107
100
|
}
|
|
108
|
-
|
|
101
|
+
|
|
109
102
|
activeSubscriptions.push(subscription);
|
|
110
103
|
}
|
|
111
|
-
|
|
104
|
+
|
|
112
105
|
return activeSubscriptions;
|
|
113
106
|
} catch (error) {
|
|
114
107
|
console.error('Error getting active subscriptions:', error);
|
|
@@ -122,8 +115,8 @@ export const getActiveSubscriptions = async (
|
|
|
122
115
|
* @returns Promise<boolean> true if user has at least one active subscription
|
|
123
116
|
*/
|
|
124
117
|
export const hasActiveSubscriptions = async (
|
|
125
|
-
subscriptionIds?: string[]
|
|
118
|
+
subscriptionIds?: string[]
|
|
126
119
|
): Promise<boolean> => {
|
|
127
120
|
const subscriptions = await getActiveSubscriptions(subscriptionIds);
|
|
128
121
|
return subscriptions.length > 0;
|
|
129
|
-
};
|
|
122
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -331,9 +331,8 @@ export const getAvailablePurchases = ({
|
|
|
331
331
|
),
|
|
332
332
|
android: async () => {
|
|
333
333
|
const products = await ExpoIapModule.getAvailableItemsByType('inapp');
|
|
334
|
-
const subscriptions =
|
|
335
|
-
'subs'
|
|
336
|
-
);
|
|
334
|
+
const subscriptions =
|
|
335
|
+
await ExpoIapModule.getAvailableItemsByType('subs');
|
|
337
336
|
return products.concat(subscriptions);
|
|
338
337
|
},
|
|
339
338
|
}) || (() => Promise.resolve([]))
|
|
@@ -407,7 +406,11 @@ const normalizeRequestProps = (
|
|
|
407
406
|
*/
|
|
408
407
|
export const requestPurchase = (
|
|
409
408
|
requestObj: PurchaseRequest,
|
|
410
|
-
): Promise<
|
|
409
|
+
): Promise<
|
|
410
|
+
| Purchase
|
|
411
|
+
| Purchase[]
|
|
412
|
+
| void
|
|
413
|
+
> => {
|
|
411
414
|
const {request, type = 'inapp'} = requestObj;
|
|
412
415
|
|
|
413
416
|
if (Platform.OS === 'ios') {
|
|
@@ -437,7 +440,9 @@ export const requestPurchase = (
|
|
|
437
440
|
offer,
|
|
438
441
|
);
|
|
439
442
|
|
|
440
|
-
return type === 'inapp'
|
|
443
|
+
return type === 'inapp'
|
|
444
|
+
? (purchase as Purchase)
|
|
445
|
+
: (purchase as Purchase);
|
|
441
446
|
})();
|
|
442
447
|
}
|
|
443
448
|
|
package/src/modules/android.ts
CHANGED
|
@@ -26,7 +26,7 @@ export function isProductAndroid<T extends {platform?: string}>(
|
|
|
26
26
|
* @param {string} params.sku - The product's SKU (on Android)
|
|
27
27
|
* @param {string} params.packageName - The package name of your Android app (e.g., 'com.example.app')
|
|
28
28
|
* @returns {Promise<void>}
|
|
29
|
-
*
|
|
29
|
+
*
|
|
30
30
|
* @example
|
|
31
31
|
* ```typescript
|
|
32
32
|
* await deepLinkToSubscriptionsAndroid({
|
|
@@ -43,11 +43,9 @@ export const deepLinkToSubscriptionsAndroid = async ({
|
|
|
43
43
|
packageName: string;
|
|
44
44
|
}): Promise<void> => {
|
|
45
45
|
if (!packageName) {
|
|
46
|
-
throw new Error(
|
|
47
|
-
'packageName is required for deepLinkToSubscriptionsAndroid',
|
|
48
|
-
);
|
|
46
|
+
throw new Error('packageName is required for deepLinkToSubscriptionsAndroid');
|
|
49
47
|
}
|
|
50
|
-
|
|
48
|
+
|
|
51
49
|
return Linking.openURL(
|
|
52
50
|
`https://play.google.com/store/account/subscriptions?package=${packageName}&sku=${sku}`,
|
|
53
51
|
);
|
|
@@ -120,9 +118,11 @@ export const acknowledgePurchaseAndroid = ({
|
|
|
120
118
|
* Open the Google Play Store to redeem offer codes (Android only).
|
|
121
119
|
* Note: Google Play does not provide a direct API to redeem codes within the app.
|
|
122
120
|
* This function opens the Play Store where users can manually enter their codes.
|
|
123
|
-
*
|
|
121
|
+
*
|
|
124
122
|
* @returns {Promise<void>}
|
|
125
123
|
*/
|
|
126
124
|
export const openRedeemOfferCodeAndroid = async (): Promise<void> => {
|
|
127
|
-
return Linking.openURL(
|
|
125
|
+
return Linking.openURL(
|
|
126
|
+
`https://play.google.com/redeem?code=`
|
|
127
|
+
);
|
|
128
128
|
};
|
package/src/modules/ios.ts
CHANGED
|
@@ -5,7 +5,10 @@ import {purchaseUpdatedListener} from '..';
|
|
|
5
5
|
import ExpoIapModule from '../ExpoIapModule';
|
|
6
6
|
|
|
7
7
|
// Types
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Purchase,
|
|
10
|
+
PurchaseError,
|
|
11
|
+
} from '../ExpoIap.types';
|
|
9
12
|
import type {
|
|
10
13
|
ProductStatusIOS,
|
|
11
14
|
AppTransactionIOS,
|
|
@@ -133,7 +136,9 @@ export const subscriptionStatusIOS = (
|
|
|
133
136
|
*
|
|
134
137
|
* @platform iOS
|
|
135
138
|
*/
|
|
136
|
-
export const currentEntitlementIOS = (
|
|
139
|
+
export const currentEntitlementIOS = (
|
|
140
|
+
sku: string,
|
|
141
|
+
): Promise<Purchase> => {
|
|
137
142
|
return ExpoIapModule.currentEntitlement(sku);
|
|
138
143
|
};
|
|
139
144
|
|
|
@@ -31,7 +31,7 @@ type ProductSubscriptionAndroidOfferDetail = {
|
|
|
31
31
|
export type ProductAndroid = ProductCommon & {
|
|
32
32
|
nameAndroid: string;
|
|
33
33
|
oneTimePurchaseOfferDetailsAndroid?: ProductAndroidOneTimePurchaseOfferDetail;
|
|
34
|
-
platform:
|
|
34
|
+
platform: "android";
|
|
35
35
|
subscriptionOfferDetailsAndroid?: ProductSubscriptionAndroidOfferDetail[];
|
|
36
36
|
/**
|
|
37
37
|
* @deprecated Use `nameAndroid` instead. This field will be removed in v2.9.0.
|
|
@@ -144,7 +144,7 @@ export const PurchaseStateAndroid = PurchaseAndroidState;
|
|
|
144
144
|
|
|
145
145
|
// Legacy naming for backward compatibility
|
|
146
146
|
export type ProductPurchaseAndroid = PurchaseCommon & {
|
|
147
|
-
platform:
|
|
147
|
+
platform: "android";
|
|
148
148
|
/**
|
|
149
149
|
* @deprecated Use `purchaseToken` instead. This field will be removed in a future version.
|
|
150
150
|
*/
|
|
@@ -167,8 +167,7 @@ export type PurchaseAndroid = ProductPurchaseAndroid;
|
|
|
167
167
|
/**
|
|
168
168
|
* @deprecated Use `ProductAndroidOneTimePurchaseOfferDetail` instead. This type will be removed in v2.9.0.
|
|
169
169
|
*/
|
|
170
|
-
export type OneTimePurchaseOfferDetails =
|
|
171
|
-
ProductAndroidOneTimePurchaseOfferDetail;
|
|
170
|
+
export type OneTimePurchaseOfferDetails = ProductAndroidOneTimePurchaseOfferDetail;
|
|
172
171
|
|
|
173
172
|
/**
|
|
174
173
|
* @deprecated Use `ProductSubscriptionAndroidOfferDetail` instead. This type will be removed in v2.9.0.
|
|
@@ -30,7 +30,7 @@ export type ProductIOS = ProductCommon & {
|
|
|
30
30
|
displayNameIOS: string;
|
|
31
31
|
isFamilyShareableIOS: boolean;
|
|
32
32
|
jsonRepresentationIOS: string;
|
|
33
|
-
platform:
|
|
33
|
+
platform: "ios";
|
|
34
34
|
subscriptionInfoIOS?: SubscriptionInfo;
|
|
35
35
|
/**
|
|
36
36
|
* @deprecated Use `displayNameIOS` instead. This field will be removed in v2.9.0.
|
|
@@ -69,7 +69,7 @@ export type ProductSubscriptionIOS = ProductIOS & {
|
|
|
69
69
|
introductoryPricePaymentModeIOS?: PaymentMode;
|
|
70
70
|
introductoryPriceNumberOfPeriodsIOS?: string;
|
|
71
71
|
introductoryPriceSubscriptionPeriodIOS?: SubscriptionIosPeriod;
|
|
72
|
-
platform:
|
|
72
|
+
platform: "ios";
|
|
73
73
|
subscriptionPeriodNumberIOS?: string;
|
|
74
74
|
subscriptionPeriodUnitIOS?: SubscriptionIosPeriod;
|
|
75
75
|
/**
|
|
@@ -140,7 +140,7 @@ export type ProductStatusIOS = {
|
|
|
140
140
|
// Legacy naming for backward compatibility
|
|
141
141
|
export type ProductPurchaseIOS = PurchaseCommon & {
|
|
142
142
|
// iOS basic fields
|
|
143
|
-
platform:
|
|
143
|
+
platform: "ios";
|
|
144
144
|
quantityIOS?: number;
|
|
145
145
|
originalTransactionDateIOS?: number;
|
|
146
146
|
originalTransactionIdentifierIOS?: string;
|
|
@@ -179,6 +179,7 @@ export type ProductPurchaseIOS = PurchaseCommon & {
|
|
|
179
179
|
// Preferred naming
|
|
180
180
|
export type PurchaseIOS = ProductPurchaseIOS;
|
|
181
181
|
|
|
182
|
+
|
|
182
183
|
export type AppTransactionIOS = {
|
|
183
184
|
appTransactionId?: string; // Only available in iOS 18.4+
|
|
184
185
|
originalPlatform?: string; // Only available in iOS 18.4+
|
package/src/useIAP.ts
CHANGED
|
@@ -97,7 +97,9 @@ type UseIap = {
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
export interface UseIAPOptions {
|
|
100
|
-
onPurchaseSuccess?: (
|
|
100
|
+
onPurchaseSuccess?: (
|
|
101
|
+
purchase: Purchase,
|
|
102
|
+
) => void;
|
|
101
103
|
onPurchaseError?: (error: PurchaseError) => void;
|
|
102
104
|
onSyncError?: (error: Error) => void;
|
|
103
105
|
shouldAutoSyncPurchases?: boolean; // New option to control auto-syncing
|
|
@@ -109,8 +111,12 @@ export function useIAP(options?: UseIAPOptions): UseIap {
|
|
|
109
111
|
const [products, setProducts] = useState<Product[]>([]);
|
|
110
112
|
const [promotedProductsIOS] = useState<Purchase[]>([]);
|
|
111
113
|
const [subscriptions, setSubscriptions] = useState<SubscriptionProduct[]>([]);
|
|
112
|
-
const [purchaseHistories, setPurchaseHistories] = useState<Purchase[]>(
|
|
113
|
-
|
|
114
|
+
const [purchaseHistories, setPurchaseHistories] = useState<Purchase[]>(
|
|
115
|
+
[],
|
|
116
|
+
);
|
|
117
|
+
const [availablePurchases, setAvailablePurchases] = useState<
|
|
118
|
+
Purchase[]
|
|
119
|
+
>([]);
|
|
114
120
|
const [currentPurchase, setCurrentPurchase] = useState<Purchase>();
|
|
115
121
|
const [promotedProductIOS, setPromotedProductIOS] = useState<Product>();
|
|
116
122
|
const [currentPurchaseError, setCurrentPurchaseError] =
|