expo-iap 2.1.0 → 2.2.0-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.
Files changed (42) hide show
  1. package/README.md +8 -27
  2. package/android/src/main/java/expo/modules/iap/ExpoIapModule.kt +10 -9
  3. package/build/ExpoIap.types.d.ts +31 -40
  4. package/build/ExpoIap.types.d.ts.map +1 -1
  5. package/build/ExpoIap.types.js +0 -11
  6. package/build/ExpoIap.types.js.map +1 -1
  7. package/build/index.d.ts +2 -4
  8. package/build/index.d.ts.map +1 -1
  9. package/build/index.js +32 -46
  10. package/build/index.js.map +1 -1
  11. package/build/modules/android.d.ts +12 -4
  12. package/build/modules/android.d.ts.map +1 -1
  13. package/build/modules/android.js +8 -4
  14. package/build/modules/android.js.map +1 -1
  15. package/build/modules/ios.d.ts +15 -7
  16. package/build/modules/ios.d.ts.map +1 -1
  17. package/build/modules/ios.js +9 -5
  18. package/build/modules/ios.js.map +1 -1
  19. package/build/types/ExpoIapAndroid.types.d.ts +31 -31
  20. package/build/types/ExpoIapAndroid.types.d.ts.map +1 -1
  21. package/build/types/ExpoIapAndroid.types.js +6 -0
  22. package/build/types/ExpoIapAndroid.types.js.map +1 -1
  23. package/build/types/ExpoIapIos.types.d.ts +31 -34
  24. package/build/types/ExpoIapIos.types.d.ts.map +1 -1
  25. package/build/types/ExpoIapIos.types.js.map +1 -1
  26. package/build/useIap.d.ts +1 -2
  27. package/build/useIap.d.ts.map +1 -1
  28. package/build/useIap.js +3 -3
  29. package/build/useIap.js.map +1 -1
  30. package/bun.lockb +0 -0
  31. package/iap.md +161 -0
  32. package/ios/ExpoIapModule.swift +116 -30
  33. package/package.json +5 -5
  34. package/plugin/build/withIAP.js +29 -2
  35. package/plugin/src/withIAP.ts +41 -4
  36. package/src/ExpoIap.types.ts +48 -48
  37. package/src/index.ts +48 -96
  38. package/src/modules/android.ts +16 -12
  39. package/src/modules/ios.ts +20 -17
  40. package/src/types/ExpoIapAndroid.types.ts +37 -33
  41. package/src/types/ExpoIapIos.types.ts +36 -40
  42. package/src/useIap.ts +5 -8
package/src/index.ts CHANGED
@@ -2,7 +2,6 @@
2
2
  // and on native platforms to ExpoIap.ts
3
3
  import {NativeModulesProxy, EventEmitter} from 'expo-modules-core';
4
4
  import {Platform} from 'react-native';
5
-
6
5
  import {
7
6
  Product,
8
7
  ProductPurchase,
@@ -21,13 +20,14 @@ import {
21
20
  } from './types/ExpoIapAndroid.types';
22
21
  import {
23
22
  PaymentDiscount,
24
- ProductIos,
25
23
  RequestPurchaseIosProps,
26
24
  RequestSubscriptionIosProps,
27
- SubscriptionProductIos,
28
- TransactionSk2,
29
25
  } from './types/ExpoIapIos.types';
30
- import {isProductIos} from './modules/ios';
26
+ import {isProductIos, isSubscriptionProductIos} from './modules/ios';
27
+ import {
28
+ isProductAndroid,
29
+ isSubscriptionProductAndroid,
30
+ } from './modules/android';
31
31
 
32
32
  export * from './modules/android';
33
33
  export * from './modules/ios';
@@ -70,22 +70,25 @@ export function initConnection() {
70
70
  }
71
71
 
72
72
  export const getProducts = async (skus: string[]): Promise<Product[]> => {
73
+ console.log('getProducts', skus);
73
74
  if (!skus?.length) {
74
75
  return Promise.reject(new Error('"skus" is required'));
75
76
  }
76
77
 
77
78
  return Platform.select({
78
79
  ios: async () => {
79
- const items = (await ExpoIapModule.getItems(skus)) as ProductIos[];
80
- return items.filter((item: ProductIos) => isProductIos(item));
80
+ const items = await ExpoIapModule.getItems(skus);
81
+ console.log('items', items);
82
+ return items.filter((item: unknown) => isProductIos<Product>(item));
81
83
  },
82
84
  android: async () => {
83
85
  const products = await ExpoIapModule.getItemsByType(
84
86
  ProductType.InAppPurchase,
85
87
  skus,
86
88
  );
87
-
88
- return products;
89
+ return products.filter((product: unknown) =>
90
+ isProductAndroid<Product>(product),
91
+ );
89
92
  },
90
93
  default: () => Promise.reject(new Error('Unsupported Platform')),
91
94
  })();
@@ -99,15 +102,33 @@ export const getSubscriptions = async (
99
102
  }
100
103
 
101
104
  return Platform.select({
102
- ios: async (): Promise<SubscriptionProductIos[]> => {
103
- const items: SubscriptionProductIos[] = (
104
- (await ExpoIapModule.getItems(skus)) as SubscriptionProductIos[]
105
- ).filter((item: SubscriptionProductIos) => skus.includes(item.id));
106
-
107
- return items;
105
+ ios: async () => {
106
+ const rawItems = await ExpoIapModule.getItems(skus);
107
+
108
+ return rawItems.filter((item: unknown) => {
109
+ if (!isSubscriptionProductIos(item)) return false;
110
+ return (
111
+ typeof item === 'object' &&
112
+ item !== null &&
113
+ 'id' in item &&
114
+ typeof item.id === 'string' &&
115
+ skus.includes(item.id)
116
+ );
117
+ }) as SubscriptionProduct[];
108
118
  },
109
119
  android: async () => {
110
- return ExpoIapModule.getItemsByType('subs', skus);
120
+ const rawItems = await ExpoIapModule.getItemsByType('subs', skus);
121
+
122
+ return rawItems.filter((item: unknown) => {
123
+ if (!isSubscriptionProductAndroid(item)) return false;
124
+ return (
125
+ typeof item === 'object' &&
126
+ item !== null &&
127
+ 'id' in item &&
128
+ typeof item.id === 'string' &&
129
+ skus.includes(item.id)
130
+ );
131
+ }) as SubscriptionProduct[];
111
132
  },
112
133
  default: () => Promise.reject(new Error('Unsupported Platform')),
113
134
  })();
@@ -119,11 +140,9 @@ export async function endConnection(): Promise<boolean> {
119
140
 
120
141
  export const getPurchaseHistory = ({
121
142
  alsoPublishToEventListener = false,
122
- automaticallyFinishRestoredTransactions = true,
123
143
  onlyIncludeActiveItems = false,
124
144
  }: {
125
145
  alsoPublishToEventListener?: boolean;
126
- automaticallyFinishRestoredTransactions?: boolean;
127
146
  onlyIncludeActiveItems?: boolean;
128
147
  } = {}): Promise<ProductPurchase[]> =>
129
148
  (
@@ -150,11 +169,9 @@ export const getPurchaseHistory = ({
150
169
 
151
170
  export const getAvailablePurchases = ({
152
171
  alsoPublishToEventListener = false,
153
- automaticallyFinishRestoredTransactions = false,
154
172
  onlyIncludeActiveItems = true,
155
173
  }: {
156
174
  alsoPublishToEventListener?: boolean;
157
- automaticallyFinishRestoredTransactions?: boolean;
158
175
  onlyIncludeActiveItems?: boolean;
159
176
  } = {}): Promise<ProductPurchase[]> =>
160
177
  (
@@ -193,43 +210,6 @@ const offerToRecordIos = (
193
210
  };
194
211
  };
195
212
 
196
- const iosTransactionToPurchaseMap = ({
197
- id,
198
- originalPurchaseDate,
199
- productID,
200
- purchaseDate,
201
- purchasedQuantity,
202
- originalID,
203
- verificationResult,
204
- appAccountToken,
205
- jsonRepresentation,
206
- }: TransactionSk2): Purchase => {
207
- let transactionReasonIOS;
208
-
209
- try {
210
- if (jsonRepresentation) {
211
- const transactionData = JSON.parse(jsonRepresentation);
212
- transactionReasonIOS = transactionData.transactionReason;
213
- }
214
- } catch (e) {
215
- console.log('SK2 Error parsing jsonRepresentation', e);
216
- }
217
- const purchase: Purchase = {
218
- productId: productID,
219
- transactionId: String(id),
220
- transactionDate: purchaseDate, //??
221
- transactionReceipt: '', // Not available
222
- purchaseToken: '', //Not available
223
- quantityIOS: purchasedQuantity,
224
- originalTransactionDateIOS: originalPurchaseDate,
225
- originalTransactionIdentifierIOS: originalID,
226
- verificationResultIOS: verificationResult ?? '',
227
- appAccountToken: appAccountToken ?? '',
228
- transactionReasonIOS: transactionReasonIOS ?? '',
229
- };
230
- return purchase;
231
- };
232
-
233
213
  export const requestPurchase = (
234
214
  request: RequestPurchaseIosProps | RequestPurchaseAndroidProps,
235
215
  ): Promise<ProductPurchase | ProductPurchase[] | void> =>
@@ -240,31 +220,17 @@ export const requestPurchase = (
240
220
  throw new Error('sku is required for iOS purchase');
241
221
  }
242
222
 
243
- const {
244
- sku,
245
- andDangerouslyFinishTransactionAutomaticallyIOS = false,
246
- appAccountToken,
247
- quantity,
248
- withOffer,
249
- } = request;
250
-
251
- if (andDangerouslyFinishTransactionAutomaticallyIOS) {
252
- console.warn(
253
- 'You are dangerously allowing expo-iap to finish your transaction automatically. You should set andDangerouslyFinishTransactionAutomatically to false when calling requestPurchase and call finishTransaction manually when you have delivered the purchased goods to the user. It defaults to true to provide backwards compatibility. Will default to false in version 4.0.0.',
254
- );
255
- }
223
+ const {sku, appAccountToken, quantity, withOffer} = request;
256
224
 
257
225
  const offer = offerToRecordIos(withOffer);
258
226
 
259
- const result = await ExpoIapModule.buyProduct(
227
+ const purchase = await ExpoIapModule.buyProduct(
260
228
  sku,
261
- andDangerouslyFinishTransactionAutomaticallyIOS,
262
229
  appAccountToken,
263
230
  quantity ?? -1,
264
231
  offer,
265
232
  );
266
233
 
267
- const purchase = iosTransactionToPurchaseMap(result);
268
234
  return Promise.resolve(purchase);
269
235
  },
270
236
  android: async () => {
@@ -303,35 +269,21 @@ export const requestSubscription = (
303
269
  throw new Error('sku is required for iOS subscriptions');
304
270
  }
305
271
 
306
- const {
307
- sku,
308
- andDangerouslyFinishTransactionAutomaticallyIOS = false,
309
- appAccountToken,
310
- quantity,
311
- withOffer,
312
- } = request as RequestSubscriptionIosProps;
313
-
314
- if (andDangerouslyFinishTransactionAutomaticallyIOS) {
315
- console.warn(
316
- 'You are dangerously allowing expo-iap to finish your transaction automatically. You should set andDangerouslyFinishTransactionAutomatically to false when calling requestPurchase and call finishTransaction manually when you have delivered the purchased goods to the user. It defaults to true to provide backwards compatibility. Will default to false in version 4.0.0.',
317
- );
318
- }
272
+ const {sku, appAccountToken, quantity, withOffer} =
273
+ request as RequestSubscriptionIosProps;
319
274
 
320
275
  const offer = offerToRecordIos(withOffer);
321
276
 
322
- const purchase = iosTransactionToPurchaseMap(
323
- await ExpoIapModule.buyProduct(
324
- sku,
325
- andDangerouslyFinishTransactionAutomaticallyIOS,
326
- appAccountToken,
327
- quantity ?? -1,
328
- offer,
329
- ),
277
+ const purchase = await ExpoIapModule.buyProduct(
278
+ sku,
279
+ appAccountToken,
280
+ quantity ?? -1,
281
+ offer,
330
282
  );
331
- return Promise.resolve(purchase);
283
+
284
+ return Promise.resolve(purchase as SubscriptionPurchase);
332
285
  },
333
286
  android: async () => {
334
- console.log('requestSubscription', request);
335
287
  const {
336
288
  skus,
337
289
  isOfferPersonalized,
@@ -1,20 +1,24 @@
1
1
  import {Linking} from 'react-native';
2
- import {Product, PurchaseResult, SubscriptionProduct} from '../ExpoIap.types';
3
- import {
4
- ProductAndroid,
5
- ReceiptAndroid,
6
- SubscriptionProductAndroid,
7
- } from '../types/ExpoIapAndroid.types';
2
+ import {PurchaseResult} from '../ExpoIap.types';
3
+ import {ReceiptAndroid} from '../types/ExpoIapAndroid.types';
8
4
  import ExpoIapModule from '../ExpoIapModule';
9
5
 
10
- export function isProductAndroid(product: Product): product is ProductAndroid {
11
- return (product as ProductAndroid)?.title !== undefined;
6
+ // Type guards
7
+ export function isProductAndroid<T extends {platform?: string}>(
8
+ item: unknown,
9
+ ): item is T & {platform: 'android'} {
10
+ return (
11
+ item != null &&
12
+ typeof item === 'object' &&
13
+ 'platform' in item &&
14
+ item.platform === 'android'
15
+ );
12
16
  }
13
17
 
14
- export function isSubscriptionProductAndroid(
15
- product: SubscriptionProduct,
16
- ): product is SubscriptionProductAndroid {
17
- return (product as SubscriptionProductAndroid)?.title !== undefined;
18
+ export function isSubscriptionProductAndroid<T extends {platform?: string}>(
19
+ item: unknown,
20
+ ): item is T & {platform: 'android'} {
21
+ return isProductAndroid(item);
18
22
  }
19
23
 
20
24
  /**
@@ -1,16 +1,11 @@
1
1
  import {Platform} from 'react-native';
2
2
  import {emitter, IapEvent} from '..';
3
- import {Product, PurchaseError, SubscriptionProduct} from '../ExpoIap.types';
4
- import type {
5
- ProductIos,
6
- ProductStatusIos,
7
- SubscriptionProductIos,
8
- TransactionSk2,
9
- } from '../types/ExpoIapIos.types';
3
+ import {ProductPurchase, PurchaseError} from '../ExpoIap.types';
4
+ import type {ProductStatusIos} from '../types/ExpoIapIos.types';
10
5
  import ExpoIapModule from '../ExpoIapModule';
11
6
 
12
7
  export type TransactionEvent = {
13
- transaction?: TransactionSk2;
8
+ transaction?: ProductPurchase;
14
9
  error?: PurchaseError;
15
10
  };
16
11
 
@@ -25,17 +20,25 @@ export const transactionUpdatedIos = (
25
20
  return emitter.addListener(IapEvent.TransactionIapUpdated, listener);
26
21
  };
27
22
 
28
- // Functions
29
- export function isProductIos(product: Product): product is ProductIos {
30
- return (product as ProductIos)?.displayName !== undefined;
23
+ // Type guards
24
+ export function isProductIos<T extends {platform?: string}>(
25
+ item: unknown,
26
+ ): item is T & {platform: 'ios'} {
27
+ return (
28
+ item != null &&
29
+ typeof item === 'object' &&
30
+ 'platform' in item &&
31
+ item.platform === 'ios'
32
+ );
31
33
  }
32
34
 
33
- export function isSubscriptionProductIos(
34
- product: SubscriptionProduct,
35
- ): product is SubscriptionProductIos {
36
- return (product as SubscriptionProductIos)?.displayName !== undefined;
35
+ export function isSubscriptionProductIos<T extends {platform?: string}>(
36
+ item: unknown,
37
+ ): item is T & {platform: 'ios'} {
38
+ return isProductIos(item);
37
39
  }
38
40
 
41
+ // Functions
39
42
  /**
40
43
  * Sync state with Appstore (iOS only)
41
44
  * https://developer.apple.com/documentation/storekit/appstore/3791906-sync
@@ -58,13 +61,13 @@ export const subscriptionStatus = (sku: string): Promise<ProductStatusIos[]> =>
58
61
  /**
59
62
  *
60
63
  */
61
- export const currentEntitlement = (sku: string): Promise<TransactionSk2> =>
64
+ export const currentEntitlement = (sku: string): Promise<ProductPurchase> =>
62
65
  ExpoIapModule.currentEntitlement(sku);
63
66
 
64
67
  /**
65
68
  *
66
69
  */
67
- export const latestTransaction = (sku: string): Promise<TransactionSk2> =>
70
+ export const latestTransaction = (sku: string): Promise<ProductPurchase> =>
68
71
  ExpoIapModule.latestTransaction(sku);
69
72
 
70
73
  /**
@@ -1,63 +1,48 @@
1
+ import {PurchaseBase, ProductBase} from '../ExpoIap.types';
2
+
1
3
  type OneTimePurchaseOfferDetails = {
2
4
  priceCurrencyCode: string;
3
5
  formattedPrice: string;
4
6
  priceAmountMicros: string;
5
7
  };
6
8
 
7
- type SubscriptionOfferDetail = {
8
- basePlanId: string;
9
- offerId: string;
10
- offerToken: string;
11
- offerTags: string[];
12
- pricingPhases: PricingPhases;
13
- };
14
-
15
- type PricingPhases = {
16
- pricingPhaseList: PricingPhase[];
17
- };
18
-
19
- type PricingPhase = {
9
+ type PricingPhaseAndroid = {
20
10
  formattedPrice: string;
21
11
  priceCurrencyCode: string;
12
+ // P1W, P1M, P1Y
22
13
  billingPeriod: string;
23
14
  billingCycleCount: number;
24
15
  priceAmountMicros: string;
25
16
  recurrenceMode: number;
26
17
  };
27
18
 
28
- export type ProductAndroid = {
29
- productId: string;
30
- title: string;
31
- description: string;
32
- productType: string;
19
+ type PricingPhasesAndroid = {
20
+ pricingPhaseList: PricingPhaseAndroid[];
21
+ };
22
+
23
+ type SubscriptionOfferDetail = {
24
+ basePlanId: string;
25
+ offerId: string;
26
+ offerToken: string;
27
+ offerTags: string[];
28
+ pricingPhases: PricingPhasesAndroid;
29
+ };
30
+
31
+ export type ProductAndroid = ProductBase & {
33
32
  name: string;
34
33
  oneTimePurchaseOfferDetails?: OneTimePurchaseOfferDetails;
35
34
  subscriptionOfferDetails?: SubscriptionOfferDetail[];
36
35
  };
37
36
 
38
- type PricingPhaseAndroid = {
39
- formattedPrice: string;
40
- priceCurrencyCode: string;
41
- // P1W, P1M, P1Y
42
- billingPeriod: string;
43
- billingCycleCount: number;
44
- priceAmountMicros: string;
45
- recurrenceMode: number;
46
- };
47
-
48
37
  type SubscriptionOfferAndroid = {
49
38
  basePlanId: string;
50
39
  offerId: string | null;
51
40
  offerToken: string;
52
- pricingPhases: {pricingPhaseList: PricingPhaseAndroid[]};
41
+ pricingPhases: PricingPhasesAndroid;
53
42
  offerTags: string[];
54
43
  };
55
44
 
56
45
  export type SubscriptionProductAndroid = ProductAndroid & {
57
- name: string;
58
- title: string;
59
- description: string;
60
- productId: string;
61
46
  subscriptionOfferDetails: SubscriptionOfferAndroid[];
62
47
  };
63
48
 
@@ -121,3 +106,22 @@ export enum FeatureTypeAndroid {
121
106
  /** Subscriptions update/replace. */
122
107
  SUBSCRIPTIONS_UPDATE = 'SUBSCRIPTIONS_UPDATE',
123
108
  }
109
+
110
+ export enum PurchaseStateAndroid {
111
+ UNSPECIFIED_STATE = 0,
112
+ PURCHASED = 1,
113
+ PENDING = 2,
114
+ }
115
+
116
+ export type ProductPurchaseAndroid = PurchaseBase & {
117
+ ids?: string[];
118
+ dataAndroid?: string;
119
+ signatureAndroid?: string;
120
+ autoRenewingAndroid?: boolean;
121
+ purchaseStateAndroid?: PurchaseStateAndroid;
122
+ isAcknowledgedAndroid?: boolean;
123
+ packageNameAndroid?: string;
124
+ developerPayloadAndroid?: string;
125
+ obfuscatedAccountIdAndroid?: string;
126
+ obfuscatedProfileIdAndroid?: string;
127
+ };
@@ -1,3 +1,5 @@
1
+ import {PurchaseBase, ProductBase} from '../ExpoIap.types';
2
+
1
3
  type SubscriptionIosPeriod = 'DAY' | 'WEEK' | 'MONTH' | 'YEAR' | '';
2
4
  type PaymentMode = '' | 'FREETRIAL' | 'PAYASYOUGO' | 'PAYUPFRONT';
3
5
 
@@ -18,22 +20,18 @@ type SubscriptionInfo = {
18
20
  subscriptionPeriod: SubscriptionIosPeriod;
19
21
  };
20
22
 
21
- export type ProductIos = {
22
- currency: string;
23
- description: string;
23
+ export type ProductIos = ProductBase & {
24
24
  displayName: string;
25
25
  displayPrice: string;
26
- id: string;
27
- type: 'autoRenewable' | 'consumable' | 'nonConsumable' | 'nonRenewable';
26
+ type: 'autoRenewable' | 'consumable' | 'nonConsumable' | 'nonRenewable'; // Maps to 'type' in base Product
28
27
  isFamilyShareable: boolean;
29
28
  jsonRepresentation: string;
30
- price: number;
31
29
  subscription: SubscriptionInfo;
32
30
  introductoryPriceNumberOfPeriodsIOS?: string;
33
31
  introductoryPriceSubscriptionPeriodIOS?: SubscriptionIosPeriod;
34
32
  };
35
33
 
36
- type Discount = {
34
+ export type Discount = {
37
35
  identifier: string;
38
36
  type: string;
39
37
  numberOfPeriods: string;
@@ -59,22 +57,18 @@ export type PaymentDiscount = {
59
57
  * A string used to uniquely identify a discount offer for a product.
60
58
  */
61
59
  identifier: string;
62
-
63
60
  /**
64
61
  * A string that identifies the key used to generate the signature.
65
62
  */
66
63
  keyIdentifier: string;
67
-
68
64
  /**
69
65
  * A universally unique ID (UUID) value that you define.
70
66
  */
71
67
  nonce: string;
72
-
73
68
  /**
74
69
  * A UTF-8 string representing the properties of a specific discount offer, cryptographically signed.
75
70
  */
76
71
  signature: string;
77
-
78
72
  /**
79
73
  * The date and time of the signature's creation in milliseconds, formatted in Unix epoch time.
80
74
  */
@@ -83,7 +77,6 @@ export type PaymentDiscount = {
83
77
 
84
78
  export type RequestPurchaseIosProps = {
85
79
  sku: string;
86
- andDangerouslyFinishTransactionAutomaticallyIOS?: boolean;
87
80
  /**
88
81
  * UUID representing user account
89
82
  */
@@ -94,34 +87,6 @@ export type RequestPurchaseIosProps = {
94
87
 
95
88
  export type RequestSubscriptionIosProps = RequestPurchaseIosProps;
96
89
 
97
- export type TransactionSk2 = {
98
- appAccountToken: string;
99
- appBundleID: string;
100
- debugDescription: string;
101
- deviceVerification: string;
102
- deviceVerificationNonce: string;
103
- expirationDate: number;
104
- environment?: 'Production' | 'Sandbox' | 'Xcode'; // Could be undefined in some cases on iOS 15, but it's stable since iOS 16
105
- id: number;
106
- isUpgraded: boolean;
107
- jsonRepresentation: string;
108
- offerID: string;
109
- offerType: string;
110
- originalID: string;
111
- originalPurchaseDate: number;
112
- ownershipType: string;
113
- productID: string;
114
- productType: string;
115
- purchaseDate: number;
116
- purchasedQuantity: number;
117
- revocationDate: number;
118
- revocationReason: string;
119
- signedDate: number;
120
- subscriptionGroupID: number;
121
- webOrderLineItemID: number;
122
- verificationResult?: string;
123
- };
124
-
125
90
  type SubscriptionStatus =
126
91
  | 'expired'
127
92
  | 'inBillingRetryPeriod'
@@ -139,3 +104,34 @@ export type ProductStatusIos = {
139
104
  state: SubscriptionStatus;
140
105
  renewalInfo?: RenewalInfo;
141
106
  };
107
+
108
+ export type ProductPurchaseIos = PurchaseBase & {
109
+ // iOS basic fields
110
+ quantityIos?: number;
111
+ originalTransactionDateIos?: number;
112
+ originalTransactionIdentifierIos?: string;
113
+ verificationResultIos?: string;
114
+ appAccountToken?: string;
115
+ // iOS additional fields from StoreKit 2
116
+ expirationDateIos?: number;
117
+ webOrderLineItemIdIos?: number;
118
+ environmentIos?: string;
119
+ storefrontCountryCodeIos?: string;
120
+ appBundleIdIos?: string;
121
+ productTypeIos?: string;
122
+ subscriptionGroupIdIos?: string;
123
+ isUpgradedIos?: boolean;
124
+ ownershipTypeIos?: string;
125
+ reasonIos?: string;
126
+ reasonStringRepresentationIos?: string;
127
+ transactionReasonIos?: 'PURCHASE' | 'RENEWAL' | string;
128
+ revocationDateIos?: number;
129
+ revocationReasonIos?: string;
130
+ offerIos?: {
131
+ id: string;
132
+ type: string;
133
+ paymentMode: string;
134
+ };
135
+ priceIos?: number;
136
+ currencyIos?: string;
137
+ };
package/src/useIap.ts CHANGED
@@ -9,7 +9,6 @@ import {
9
9
  getPurchaseHistory,
10
10
  getSubscriptions,
11
11
  } from './';
12
-
13
12
  import {useCallback, useEffect, useState} from 'react';
14
13
  import {
15
14
  Product,
@@ -21,13 +20,12 @@ import {
21
20
  SubscriptionPurchase,
22
21
  } from './ExpoIap.types';
23
22
  import {TransactionEvent} from './modules/ios';
24
- import {TransactionSk2} from './types/ExpoIapIos.types';
25
23
  import {Subscription} from 'expo-modules-core';
26
24
 
27
25
  type IAP_STATUS = {
28
26
  connected: boolean;
29
27
  products: Product[];
30
- promotedProductsIOS: TransactionSk2[];
28
+ promotedProductsIOS: ProductPurchase[];
31
29
  subscriptions: SubscriptionProduct[];
32
30
  purchaseHistories: ProductPurchase[];
33
31
  availablePurchases: ProductPurchase[];
@@ -56,7 +54,7 @@ export function useIAP(): IAP_STATUS {
56
54
  const [connected, setConnected] = useState<boolean>(false);
57
55
  const [products, setProducts] = useState<Product[]>([]);
58
56
  const [promotedProductsIOS, setPromotedProductsIOS] = useState<
59
- TransactionSk2[]
57
+ ProductPurchase[]
60
58
  >([]);
61
59
  const [subscriptions, setSubscriptions] = useState<SubscriptionProduct[]>([]);
62
60
  const [purchaseHistories, setPurchaseHistories] = useState<ProductPurchase[]>(
@@ -66,7 +64,6 @@ export function useIAP(): IAP_STATUS {
66
64
  ProductPurchase[]
67
65
  >([]);
68
66
  const [currentPurchase, setCurrentPurchase] = useState<ProductPurchase>();
69
-
70
67
  const [currentPurchaseError, setCurrentPurchaseError] =
71
68
  useState<PurchaseError>();
72
69
 
@@ -108,17 +105,17 @@ export function useIAP(): IAP_STATUS {
108
105
  } catch (err) {
109
106
  throw err;
110
107
  } finally {
111
- if (purchase.productId === currentPurchase?.productId) {
108
+ if (purchase.id === currentPurchase?.id) {
112
109
  setCurrentPurchase(undefined);
113
110
  }
114
111
 
115
- if (purchase.productId === currentPurchaseError?.productId) {
112
+ if (purchase.id === currentPurchaseError?.productId) { // Note that PurchaseError still uses productId
116
113
  setCurrentPurchaseError(undefined);
117
114
  }
118
115
  }
119
116
  },
120
117
  [
121
- currentPurchase?.productId,
118
+ currentPurchase?.id,
122
119
  currentPurchaseError?.productId,
123
120
  setCurrentPurchase,
124
121
  setCurrentPurchaseError,