react-native-iap 11.0.0-rc.2 → 11.0.0-rc.4

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 (57) hide show
  1. package/ios/IapSerializationUtils.swift +50 -11
  2. package/ios/IapTypes.swift +1 -6
  3. package/ios/RNIapIos.m +3 -0
  4. package/ios/RNIapIos.swift +12 -3
  5. package/ios/RNIapIosSk2.m +6 -1
  6. package/ios/RNIapIosSk2.swift +37 -16
  7. package/lib/commonjs/eventEmitter.js +145 -2
  8. package/lib/commonjs/eventEmitter.js.map +1 -1
  9. package/lib/commonjs/hooks/withIAPContext.js +8 -1
  10. package/lib/commonjs/hooks/withIAPContext.js.map +1 -1
  11. package/lib/commonjs/iap.js +81 -37
  12. package/lib/commonjs/iap.js.map +1 -1
  13. package/lib/commonjs/internal/platform.js +33 -4
  14. package/lib/commonjs/internal/platform.js.map +1 -1
  15. package/lib/commonjs/modules/ios.js +5 -2
  16. package/lib/commonjs/modules/ios.js.map +1 -1
  17. package/lib/commonjs/modules/iosSk2.js.map +1 -1
  18. package/lib/commonjs/types/apple.js +24 -0
  19. package/lib/commonjs/types/apple.js.map +1 -1
  20. package/lib/commonjs/types/appleSk2.js +3 -3
  21. package/lib/commonjs/types/appleSk2.js.map +1 -1
  22. package/lib/commonjs/types/index.js.map +1 -1
  23. package/lib/module/eventEmitter.js +141 -1
  24. package/lib/module/eventEmitter.js.map +1 -1
  25. package/lib/module/hooks/withIAPContext.js +9 -2
  26. package/lib/module/hooks/withIAPContext.js.map +1 -1
  27. package/lib/module/iap.js +77 -30
  28. package/lib/module/iap.js.map +1 -1
  29. package/lib/module/internal/platform.js +25 -2
  30. package/lib/module/internal/platform.js.map +1 -1
  31. package/lib/module/modules/ios.js +5 -2
  32. package/lib/module/modules/ios.js.map +1 -1
  33. package/lib/module/modules/iosSk2.js.map +1 -1
  34. package/lib/module/types/apple.js +15 -0
  35. package/lib/module/types/apple.js.map +1 -1
  36. package/lib/module/types/appleSk2.js +3 -3
  37. package/lib/module/types/appleSk2.js.map +1 -1
  38. package/lib/module/types/index.js.map +1 -1
  39. package/lib/typescript/eventEmitter.d.ts +133 -0
  40. package/lib/typescript/hooks/withIAPContext.d.ts +2 -0
  41. package/lib/typescript/iap.d.ts +25 -4
  42. package/lib/typescript/internal/platform.d.ts +3 -1
  43. package/lib/typescript/modules/ios.d.ts +2 -1
  44. package/lib/typescript/modules/iosSk2.d.ts +3 -2
  45. package/lib/typescript/types/apple.d.ts +1 -0
  46. package/lib/typescript/types/appleSk2.d.ts +31 -2
  47. package/lib/typescript/types/index.d.ts +1 -0
  48. package/package.json +1 -1
  49. package/src/eventEmitter.ts +144 -2
  50. package/src/hooks/withIAPContext.tsx +15 -0
  51. package/src/iap.ts +55 -17
  52. package/src/internal/platform.ts +24 -2
  53. package/src/modules/ios.ts +7 -3
  54. package/src/modules/iosSk2.ts +5 -2
  55. package/src/types/apple.ts +15 -0
  56. package/src/types/appleSk2.ts +42 -5
  57. package/src/types/index.ts +1 -0
@@ -2,9 +2,22 @@ import * as IapAmazon from './modules/amazon';
2
2
  import * as IapAndroid from './modules/android';
3
3
  import * as IapIos from './modules/ios';
4
4
  import * as IapIosSk2 from './modules/iosSk2';
5
- import { enableStorekit2, isIosStorekit2 } from './internal';
5
+ import { isIosStorekit2 } from './internal';
6
6
  import { Product, ProductPurchase, PurchaseResult, RequestPurchase, RequestSubscription, Subscription, SubscriptionPurchase } from './types';
7
- export { IapAndroid, IapAmazon, IapIos, IapIosSk2, isIosStorekit2, enableStorekit2, };
7
+ export { IapAndroid, IapAmazon, IapIos, IapIosSk2, isIosStorekit2 };
8
+ /**
9
+ * STOREKIT1_MODE: Will not enable Storekit 2 even if the device supports it. Thigs will work as before,
10
+ * minimum changes required in the migration guide (default)
11
+ * HYBRID_MODE: Will enable Storekit 2 for iOS devices > 15.0 but will fallback to Sk1 on older devices
12
+ * There are some edge cases that you need to handle in this case (described in migration guide). This mode
13
+ * is for developers that are migrating to Storekit 2 but want to keep supporting older versions.
14
+ * STOREKIT2_MODE: Will *only* enable Storekit 2. This disables Storekit 1. This is for apps that
15
+ * have already targeted a min version of 15 for their app.
16
+ */
17
+ export declare type STOREKIT_OPTIONS = 'STOREKIT1_MODE' | 'STOREKIT_HYBRID_MODE' | 'STOREKIT2_MODE';
18
+ export declare const setup: ({ storekitMode, }?: {
19
+ storekitMode?: STOREKIT_OPTIONS | undefined;
20
+ }) => void;
8
21
  /**
9
22
  * Init module for purchase flow. Required on Android. In ios it will check whether user canMakePayment.
10
23
  * ## Usage
@@ -143,8 +156,12 @@ const App = () => {
143
156
  return <View />;
144
157
  };
145
158
  ```
159
+ @param {alsoPublishToEventListener}:boolean When `true`, every element will also be pushed to the purchaseUpdated listener.
160
+ Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
146
161
  */
147
- export declare const getPurchaseHistory: () => Promise<(ProductPurchase | SubscriptionPurchase)[]>;
162
+ export declare const getPurchaseHistory: ({ alsoPublishToEventListener, }?: {
163
+ alsoPublishToEventListener?: boolean | undefined;
164
+ }) => Promise<(ProductPurchase | SubscriptionPurchase)[]>;
148
165
  /**
149
166
  * Get all purchases made by the user (either non-consumable, or haven't been consumed yet)
150
167
  * ## Usage
@@ -221,9 +238,13 @@ const App = () => {
221
238
  )
222
239
  };
223
240
  ```
241
+ @param {alsoPublishToEventListener}:boolean When `true`, every element will also be pushed to the purchaseUpdated listener.
242
+ Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
224
243
  *
225
244
  */
226
- export declare const getAvailablePurchases: () => Promise<(ProductPurchase | SubscriptionPurchase)[]>;
245
+ export declare const getAvailablePurchases: ({ alsoPublishToEventListener, }?: {
246
+ alsoPublishToEventListener?: boolean | undefined;
247
+ }) => Promise<(ProductPurchase | SubscriptionPurchase)[]>;
227
248
  /**
228
249
  * Request a purchase for product. This will be received in `PurchaseUpdatedListener`.
229
250
  * Request a purchase for a product (consumables or non-consumables).
@@ -8,5 +8,7 @@ export declare const getNativeModule: () => import("..").AmazonModuleProps | imp
8
8
  export declare const isIosStorekit2: () => boolean;
9
9
  export declare const isStorekit2Avaiable: () => boolean;
10
10
  export declare const setIosNativeModule: (nativeModule: import("..").IosModuleProps | import("../modules/iosSk2").IosModulePropsSk2) => void;
11
- export declare const enableStorekit2: () => boolean;
11
+ export declare const storekit2Mode: () => boolean;
12
+ export declare const storekit1Mode: () => boolean;
13
+ export declare const storekitHybridMode: () => boolean;
12
14
  export declare const getIosModule: () => import("..").IosModuleProps | import("../modules/iosSk2").IosModulePropsSk2;
@@ -4,7 +4,7 @@ import type { PaymentDiscount } from '../types/apple';
4
4
  import type { NativeModuleProps } from './common';
5
5
  declare type getItems = (skus: Sku[]) => Promise<Product[] | Subscription[]>;
6
6
  declare type getAvailableItems = () => Promise<Purchase[]>;
7
- export declare type BuyProduct = (sku: Sku, andDangerouslyFinishTransactionAutomaticallyIOS: boolean, applicationUsername: string | undefined, quantity: number, withOffer: PaymentDiscount | undefined) => Promise<Purchase>;
7
+ export declare type BuyProduct = (sku: Sku, andDangerouslyFinishTransactionAutomaticallyIOS: boolean, applicationUsername: string | undefined, quantity: number, withOffer: Record<keyof PaymentDiscount, string> | undefined) => Promise<Purchase>;
8
8
  declare type clearTransaction = () => Promise<void>;
9
9
  declare type clearProducts = () => Promise<void>;
10
10
  declare type promotedProduct = () => Promise<Product | null>;
@@ -25,6 +25,7 @@ export interface IosModuleProps extends NativeModuleProps {
25
25
  finishTransaction: finishTransaction;
26
26
  getPendingTransactions: getPendingTransactions;
27
27
  presentCodeRedemptionSheet: presentCodeRedemptionSheet;
28
+ disable: () => Promise<null>;
28
29
  }
29
30
  /**
30
31
  * Get the current receipt base64 encoded in IOS.
@@ -2,8 +2,8 @@ import type { Product, ProductPurchase, Purchase, Sku } from '../types';
2
2
  import type { PaymentDiscountSk2, ProductSk2, ProductStatus, TransactionSk2 } from '../types/appleSk2';
3
3
  import type { NativeModuleProps } from './common';
4
4
  declare type getItems = (skus: Sku[]) => Promise<ProductSk2[]>;
5
- declare type getAvailableItems = () => Promise<Purchase[]>;
6
- export declare type BuyProduct = (sku: Sku, andDangerouslyFinishTransactionAutomaticallyIOS: boolean, applicationUsername: string | undefined, quantity: number, withOffer: PaymentDiscountSk2 | undefined) => Promise<Purchase>;
5
+ declare type getAvailableItems = (alsoPublishToEventListener?: boolean) => Promise<Purchase[]>;
6
+ export declare type BuyProduct = (sku: Sku, andDangerouslyFinishTransactionAutomaticallyIOS: boolean, applicationUsername: string | undefined, quantity: number, withOffer: Record<keyof PaymentDiscountSk2, string> | undefined) => Promise<Purchase>;
7
7
  declare type clearTransaction = () => Promise<void>;
8
8
  declare type clearProducts = () => Promise<void>;
9
9
  declare type promotedProduct = () => Promise<Product | null>;
@@ -29,6 +29,7 @@ export interface IosModulePropsSk2 extends NativeModuleProps {
29
29
  finishTransaction: finishTransaction;
30
30
  getPendingTransactions: getPendingTransactions;
31
31
  presentCodeRedemptionSheet: presentCodeRedemptionSheet;
32
+ disable: () => Promise<null>;
32
33
  }
33
34
  /**
34
35
  * Sync state with Appstore (iOS only)
@@ -23,3 +23,4 @@ export interface PaymentDiscount {
23
23
  */
24
24
  timestamp: number;
25
25
  }
26
+ export declare const offerToRecord: (offer: PaymentDiscount | undefined) => Record<keyof PaymentDiscount, string> | undefined;
@@ -1,5 +1,26 @@
1
+ import type { PurchaseError } from '../purchaseError';
1
2
  import type { ProductIOS, Purchase, SubscriptionIOS } from '.';
2
3
  import type * as Apple from './apple';
4
+ export declare type SubscriptionPeriod = {
5
+ unit: 'day' | 'week' | 'month' | 'year';
6
+ value: number;
7
+ };
8
+ export declare type PaymentMode = 'freeTrial' | 'payAsYouGo' | 'payUpFront';
9
+ export declare type SubscriptionOffer = {
10
+ displayPrice: string;
11
+ id: string;
12
+ paymentMode: PaymentMode;
13
+ period: SubscriptionPeriod;
14
+ periodCount: number;
15
+ price: number;
16
+ type: 'introductory' | 'promotional';
17
+ };
18
+ export declare type SubscriptionInfo = {
19
+ introductoryOffer?: SubscriptionOffer;
20
+ promotionalOffers?: SubscriptionOffer[];
21
+ subscriptionGroupID: string;
22
+ subscriptionPeriod: SubscriptionPeriod;
23
+ };
3
24
  export declare type ProductSk2 = {
4
25
  description: string;
5
26
  displayName: string;
@@ -8,7 +29,7 @@ export declare type ProductSk2 = {
8
29
  isFamilyShareable: boolean;
9
30
  jsonRepresentation: string;
10
31
  price: number;
11
- subscription: any;
32
+ subscription: SubscriptionInfo;
12
33
  type: 'autoRenewable' | 'consumable' | 'nonConsumable' | 'nonRenewable';
13
34
  };
14
35
  export declare const productSk2Map: ({ id, description, displayName, price, displayPrice, }: ProductSk2) => ProductIOS;
@@ -38,6 +59,14 @@ export declare type TransactionSk2 = {
38
59
  subscriptionGroupID: number;
39
60
  webOrderLineItemID: number;
40
61
  };
62
+ export declare type TransactionError = PurchaseError;
63
+ /**
64
+ * Only one of `transaction` and `error` is not undefined at the time
65
+ */
66
+ export declare type TransactionEvent = {
67
+ transaction?: TransactionSk2;
68
+ error?: TransactionError;
69
+ };
41
70
  export declare type SubscriptionStatus = 'expired' | 'inBillingRetryPeriod' | 'inGracePeriod' | 'revoked' | 'subscribed';
42
71
  export declare type ProductStatus = {
43
72
  state: SubscriptionStatus;
@@ -68,4 +97,4 @@ export interface PaymentDiscountSk2 {
68
97
  */
69
98
  timestamp: number;
70
99
  }
71
- export declare const offerSk2Map: (offer: Apple.PaymentDiscount | undefined) => PaymentDiscountSk2 | undefined;
100
+ export declare const offerSk2Map: (offer: Apple.PaymentDiscount | undefined) => Record<keyof PaymentDiscountSk2, string> | undefined;
@@ -119,6 +119,7 @@ export interface SubscriptionAndroid extends ProductCommon {
119
119
  recurrenceMode: number;
120
120
  }[];
121
121
  };
122
+ offerTags: string[];
122
123
  }[];
123
124
  }
124
125
  export interface SubscriptionIOS extends ProductCommon {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-iap",
3
- "version": "11.0.0-rc.2",
3
+ "version": "11.0.0-rc.4",
4
4
  "description": "React Native In App Purchase Module.",
5
5
  "repository": "https://github.com/dooboolab/react-native-iap",
6
6
  "author": "dooboolab <support@dooboolab.com> (https://github.com/dooboolab)",
@@ -1,6 +1,6 @@
1
1
  import {EmitterSubscription, NativeEventEmitter} from 'react-native';
2
2
 
3
- import {transactionSk2Map} from './types/appleSk2';
3
+ import {TransactionEvent, transactionSk2Map} from './types/appleSk2';
4
4
  import {isIosStorekit2} from './iap';
5
5
  import {
6
6
  getAndroidModule,
@@ -14,6 +14,35 @@ import type {Purchase} from './types';
14
14
 
15
15
  /**
16
16
  * Add IAP purchase event
17
+ * Register a callback that gets called when the store has any updates to purchases that have not yet been finished, consumed or acknowledged. Returns a React Native `EmitterSubscription` on which you can call `.remove()` to stop receiving updates. Register you listener as soon as possible and react to updates at all times.
18
+
19
+ ## Signature
20
+
21
+ ```ts
22
+ purchaseUpdatedListener((purchase: Purchase) => {});
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```tsx
28
+ import React, {useEffect} from 'react';
29
+ import {View} from 'react-native';
30
+ import {purchaseUpdatedListener} from 'react-native-iap';
31
+
32
+ const App = () => {
33
+ useEffect(() => {
34
+ const subscription = purchaseUpdatedListener((purchase: Purchase) => {
35
+ console.log(purchase);
36
+ });
37
+
38
+ return () => {
39
+ subscription.remove();
40
+ };
41
+ }, []);
42
+
43
+ return <View />;
44
+ };
45
+ ```
17
46
  */
18
47
  export const purchaseUpdatedListener = (
19
48
  listener: (event: Purchase) => void,
@@ -38,6 +67,36 @@ export const purchaseUpdatedListener = (
38
67
 
39
68
  /**
40
69
  * Add IAP purchase error event
70
+ * Register a callback that gets called when there has been an error with a purchase. Returns a React Native `EmitterSubscription` on which you can call `.remove()` to stop receiving updates.
71
+
72
+ ## Signature
73
+
74
+ ```ts
75
+ purchaseErrorListener((error: PurchaseError) => {});
76
+ ```
77
+
78
+ ## Usage
79
+
80
+ ```tsx
81
+ import React, {useEffect} from 'react';
82
+ import {View} from 'react-native';
83
+ import {purchaseErrorListener} from 'react-native-iap';
84
+
85
+ const App = () => {
86
+ useEffect(() => {
87
+ const subscription = purchaseErrorListener((error: PurchaseError) => {
88
+ console.log(error);
89
+ });
90
+
91
+ return () => {
92
+ subscription.remove();
93
+ };
94
+ }, []);
95
+
96
+ return <View />;
97
+ };
98
+ ```
99
+
41
100
  */
42
101
  export const purchaseErrorListener = (
43
102
  listener: (error: PurchaseError) => void,
@@ -48,14 +107,97 @@ export const purchaseErrorListener = (
48
107
 
49
108
  /**
50
109
  * Add IAP promoted subscription event
110
+ * Add IAP promoted subscription event.
111
+
112
+ ## Signature
113
+
114
+ ```ts
115
+ promotedProductListener((productId?: string) => {});
116
+ ```
117
+
118
+ ## Usage
119
+
120
+ ```tsx
121
+ import React, {useEffect} from 'react';
122
+ import {View} from 'react-native';
123
+ import {promotedProductListener} from 'react-native-iap';
124
+
125
+ const App = () => {
126
+ useEffect(() => {
127
+ const subscription = promotedProductListener((productId) => {
128
+ console.log(productId);
129
+ });
130
+
131
+ return () => {
132
+ subscription.remove();
133
+ };
134
+ }, []);
135
+
136
+ return <View />;
137
+ };
138
+ ```
139
+
51
140
  *
52
141
  * @platform iOS
53
142
  */
54
143
  export const promotedProductListener = (listener: () => void) => {
55
- if (isIos) {
144
+ if (isIos && !isIosStorekit2()) {
56
145
  const eventEmitter = new NativeEventEmitter(getIosModule());
57
146
  return eventEmitter.addListener('iap-promoted-product', listener);
58
147
  }
59
148
 
60
149
  return null;
61
150
  };
151
+
152
+ /**
153
+ * Updated transactions for iOS Sk2
154
+ * Register a callback that gets called when the store has any updates to transactions related to purchases that have not yet been finished, consumed or acknowledged.
155
+ * Returns a React Native `EmitterSubscription` on which you can call `.remove()` to stop receiving updates. Register you listener as soon as possible and react to updates at all times.
156
+
157
+ **Warning**
158
+ This is only available for iOS 15 and higher and Storekit 2 is activated
159
+
160
+ ## Signature
161
+
162
+ ```ts
163
+ purchaseUpdatedListener((transactionOrError: TransactionOrError) => {});
164
+ ```
165
+
166
+ ## Usage
167
+
168
+ ```tsx
169
+ import React, {useEffect} from 'react';
170
+ import {View} from 'react-native';
171
+ import {purchaseUpdatedListener} from 'react-native-iap';
172
+
173
+ const App = () => {
174
+ useEffect(() => {
175
+ const subscription = purchaseUpdatedListener((transactionOrError: TransactionOrError) => {
176
+ if(transactionOrError.transaction){
177
+ console.log("There's an update to a transaction", transactionOrError.transaction);
178
+ }else{
179
+ console.log("There's been an error with a received transaction")
180
+ }
181
+ });
182
+
183
+ return () => {
184
+ subscription.remove();
185
+ };
186
+ }, []);
187
+
188
+ return <View />;
189
+ };
190
+ ```
191
+ *
192
+ * @platform iOS (Sk2)
193
+ */
194
+ export const transactionListener = (
195
+ listener: (event: TransactionEvent) => void,
196
+ ) => {
197
+ if (isIos && isIosStorekit2()) {
198
+ const eventEmitter = new NativeEventEmitter(getIosModule());
199
+ return eventEmitter.addListener('iap-transaction-updated', listener);
200
+ }
201
+
202
+ return null;
203
+ };
@@ -4,6 +4,7 @@ import {
4
4
  promotedProductListener,
5
5
  purchaseErrorListener,
6
6
  purchaseUpdatedListener,
7
+ transactionListener,
7
8
  } from '../eventEmitter';
8
9
  import {IapIos, initConnection} from '../iap';
9
10
  import type {PurchaseError} from '../purchaseError';
@@ -14,6 +15,7 @@ import type {
14
15
  Subscription,
15
16
  SubscriptionPurchase,
16
17
  } from '../types';
18
+ import type {TransactionEvent, TransactionSk2} from '../types/appleSk2';
17
19
 
18
20
  type IAPContextType = {
19
21
  connected: boolean;
@@ -23,6 +25,7 @@ type IAPContextType = {
23
25
  purchaseHistory: Purchase[];
24
26
  availablePurchases: Purchase[];
25
27
  currentPurchase?: Purchase;
28
+ currentTransaction?: TransactionSk2;
26
29
  currentPurchaseError?: PurchaseError;
27
30
  initConnectionError?: Error;
28
31
  setProducts: (products: Product[]) => void;
@@ -63,6 +66,8 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
63
66
  [],
64
67
  );
65
68
  const [currentPurchase, setCurrentPurchase] = useState<Purchase>();
69
+ const [currentTransaction, setCurrentTransaction] =
70
+ useState<TransactionSk2>();
66
71
 
67
72
  const [currentPurchaseError, setCurrentPurchaseError] =
68
73
  useState<PurchaseError>();
@@ -78,6 +83,7 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
78
83
  purchaseHistory,
79
84
  availablePurchases,
80
85
  currentPurchase,
86
+ currentTransaction,
81
87
  currentPurchaseError,
82
88
  initConnectionError,
83
89
  setProducts,
@@ -95,6 +101,7 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
95
101
  purchaseHistory,
96
102
  availablePurchases,
97
103
  currentPurchase,
104
+ currentTransaction,
98
105
  currentPurchaseError,
99
106
  initConnectionError,
100
107
  setProducts,
@@ -127,6 +134,13 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
127
134
  },
128
135
  );
129
136
 
137
+ const transactionUpdateSubscription = transactionListener(
138
+ async (transactionOrError: TransactionEvent) => {
139
+ setCurrentPurchaseError(transactionOrError?.error);
140
+ setCurrentTransaction(transactionOrError?.transaction);
141
+ },
142
+ );
143
+
130
144
  const purchaseErrorSubscription = purchaseErrorListener(
131
145
  (error: PurchaseError) => {
132
146
  setCurrentPurchase(undefined);
@@ -147,6 +161,7 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
147
161
  purchaseUpdateSubscription.remove();
148
162
  purchaseErrorSubscription.remove();
149
163
  promotedProductSubscription?.remove();
164
+ transactionUpdateSubscription?.remove();
150
165
  };
151
166
  }, [connected]);
152
167
 
package/src/iap.ts CHANGED
@@ -4,6 +4,7 @@ import * as IapAmazon from './modules/amazon';
4
4
  import * as IapAndroid from './modules/android';
5
5
  import * as IapIos from './modules/ios';
6
6
  import * as IapIosSk2 from './modules/iosSk2';
7
+ import {offerToRecord} from './types/apple';
7
8
  import {
8
9
  offerSk2Map,
9
10
  ProductSk2,
@@ -11,13 +12,15 @@ import {
11
12
  subscriptionSk2Map,
12
13
  } from './types/appleSk2';
13
14
  import {
14
- enableStorekit2,
15
15
  fillProductsWithAdditionalData,
16
16
  getAndroidModule,
17
17
  getIosModule,
18
18
  getNativeModule,
19
19
  isAmazon,
20
20
  isIosStorekit2,
21
+ storekit1Mode,
22
+ storekit2Mode,
23
+ storekitHybridMode,
21
24
  } from './internal';
22
25
  import {
23
26
  Product,
@@ -31,19 +34,46 @@ import {
31
34
  } from './types';
32
35
  import {PurchaseStateAndroid} from './types';
33
36
 
34
- export {
35
- IapAndroid,
36
- IapAmazon,
37
- IapIos,
38
- IapIosSk2,
39
- isIosStorekit2,
40
- enableStorekit2,
41
- };
37
+ export {IapAndroid, IapAmazon, IapIos, IapIosSk2, isIosStorekit2};
42
38
 
43
39
  const {RNIapIos, RNIapIosSk2, RNIapModule, RNIapAmazonModule} = NativeModules;
44
40
  const ANDROID_ITEM_TYPE_SUBSCRIPTION = ProductType.subs;
45
41
  const ANDROID_ITEM_TYPE_IAP = ProductType.inapp;
46
42
 
43
+ /**
44
+ * STOREKIT1_MODE: Will not enable Storekit 2 even if the device supports it. Thigs will work as before,
45
+ * minimum changes required in the migration guide (default)
46
+ * HYBRID_MODE: Will enable Storekit 2 for iOS devices > 15.0 but will fallback to Sk1 on older devices
47
+ * There are some edge cases that you need to handle in this case (described in migration guide). This mode
48
+ * is for developers that are migrating to Storekit 2 but want to keep supporting older versions.
49
+ * STOREKIT2_MODE: Will *only* enable Storekit 2. This disables Storekit 1. This is for apps that
50
+ * have already targeted a min version of 15 for their app.
51
+ */
52
+ export type STOREKIT_OPTIONS =
53
+ | 'STOREKIT1_MODE'
54
+ | 'STOREKIT_HYBRID_MODE'
55
+ | 'STOREKIT2_MODE';
56
+
57
+ export const setup = ({
58
+ storekitMode = 'STOREKIT1_MODE',
59
+ }: {
60
+ storekitMode?: STOREKIT_OPTIONS;
61
+ } = {}) => {
62
+ switch (storekitMode) {
63
+ case 'STOREKIT1_MODE':
64
+ storekit1Mode();
65
+ break;
66
+ case 'STOREKIT2_MODE':
67
+ storekit2Mode();
68
+ break;
69
+ case 'STOREKIT_HYBRID_MODE':
70
+ storekitHybridMode();
71
+ break;
72
+ default:
73
+ break;
74
+ }
75
+ };
76
+
47
77
  /**
48
78
  * Init module for purchase flow. Required on Android. In ios it will check whether user canMakePayment.
49
79
  * ## Usage
@@ -248,14 +278,18 @@ const App = () => {
248
278
  return <View />;
249
279
  };
250
280
  ```
281
+ @param {alsoPublishToEventListener}:boolean When `true`, every element will also be pushed to the purchaseUpdated listener.
282
+ Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
251
283
  */
252
- export const getPurchaseHistory = (): Promise<
253
- (ProductPurchase | SubscriptionPurchase)[]
254
- > =>
284
+ export const getPurchaseHistory = ({
285
+ alsoPublishToEventListener = false,
286
+ }: {
287
+ alsoPublishToEventListener?: boolean;
288
+ } = {}): Promise<(ProductPurchase | SubscriptionPurchase)[]> =>
255
289
  (
256
290
  Platform.select({
257
291
  ios: async () => {
258
- return getIosModule().getAvailableItems();
292
+ return getIosModule().getAvailableItems(alsoPublishToEventListener);
259
293
  },
260
294
  android: async () => {
261
295
  if (RNIapAmazonModule) {
@@ -351,15 +385,19 @@ const App = () => {
351
385
  )
352
386
  };
353
387
  ```
388
+ @param {alsoPublishToEventListener}:boolean When `true`, every element will also be pushed to the purchaseUpdated listener.
389
+ Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
354
390
  *
355
391
  */
356
- export const getAvailablePurchases = (): Promise<
392
+ export const getAvailablePurchases = ({
393
+ alsoPublishToEventListener = false,
394
+ }: {alsoPublishToEventListener?: boolean} = {}): Promise<
357
395
  (ProductPurchase | SubscriptionPurchase)[]
358
396
  > =>
359
397
  (
360
398
  Platform.select({
361
399
  ios: async () => {
362
- return getIosModule().getAvailableItems();
400
+ return getIosModule().getAvailableItems(alsoPublishToEventListener);
363
401
  },
364
402
  android: async () => {
365
403
  if (RNIapAmazonModule) {
@@ -485,7 +523,7 @@ export const requestPurchase = ({
485
523
  andDangerouslyFinishTransactionAutomaticallyIOS,
486
524
  appAccountToken,
487
525
  quantity ?? -1,
488
- withOffer,
526
+ offerToRecord(withOffer),
489
527
  );
490
528
  }
491
529
  },
@@ -638,7 +676,7 @@ export const requestSubscription = ({
638
676
  andDangerouslyFinishTransactionAutomaticallyIOS,
639
677
  appAccountToken,
640
678
  quantity ?? -1,
641
- withOffer,
679
+ offerToRecord(withOffer),
642
680
  );
643
681
  }
644
682
  },
@@ -57,9 +57,10 @@ export const setIosNativeModule = (
57
57
  iosNativeModule = nativeModule;
58
58
  };
59
59
 
60
- export const enableStorekit2 = () => {
60
+ export const storekit2Mode = () => {
61
+ iosNativeModule = RNIapIosSk2;
61
62
  if (RNIapIosSk2) {
62
- iosNativeModule = RNIapIosSk2;
63
+ RNIapIos.disable();
63
64
  return true;
64
65
  }
65
66
  console.warn('Storekit 2 is not available on this device');
@@ -67,6 +68,27 @@ export const enableStorekit2 = () => {
67
68
  return false;
68
69
  };
69
70
 
71
+ export const storekit1Mode = () => {
72
+ iosNativeModule = RNIapIos;
73
+ if (RNIapIosSk2) {
74
+ RNIapIosSk2.disable();
75
+ return true;
76
+ }
77
+ return false;
78
+ };
79
+
80
+ export const storekitHybridMode = () => {
81
+ if (RNIapIosSk2) {
82
+ iosNativeModule = RNIapIosSk2;
83
+ console.info('Using Storekit 2');
84
+ return true;
85
+ } else {
86
+ iosNativeModule = RNIapIos;
87
+ console.info('Using Storekit 1');
88
+ return true;
89
+ }
90
+ };
91
+
70
92
  const checkNativeIOSAvailable = (): void => {
71
93
  if (!RNIapIos && !RNIapIosSk2) {
72
94
  throw new Error('IAP_NOT_AVAILABLE');
@@ -21,7 +21,7 @@ export type BuyProduct = (
21
21
  andDangerouslyFinishTransactionAutomaticallyIOS: boolean,
22
22
  applicationUsername: string | undefined,
23
23
  quantity: number,
24
- withOffer: PaymentDiscount | undefined,
24
+ withOffer: Record<keyof PaymentDiscount, string> | undefined,
25
25
  ) => Promise<Purchase>;
26
26
 
27
27
  type clearTransaction = () => Promise<void>;
@@ -47,6 +47,7 @@ export interface IosModuleProps extends NativeModuleProps {
47
47
  finishTransaction: finishTransaction;
48
48
  getPendingTransactions: getPendingTransactions;
49
49
  presentCodeRedemptionSheet: presentCodeRedemptionSheet;
50
+ disable: () => Promise<null>;
50
51
  }
51
52
 
52
53
  /**
@@ -84,7 +85,7 @@ export const getPromotedProductIOS = (): Promise<Product | null> => {
84
85
  if (!isIosStorekit2()) {
85
86
  return getIosModule().promotedProduct();
86
87
  } else {
87
- return Promise.reject('Only available on SK1');
88
+ return Promise.reject('Only available on Sk1');
88
89
  }
89
90
  };
90
91
 
@@ -146,7 +147,10 @@ export const validateReceiptIos = async ({
146
147
  ? 'https://sandbox.itunes.apple.com/verifyReceipt'
147
148
  : 'https://buy.itunes.apple.com/verifyReceipt';
148
149
 
149
- return await enhancedFetch<ReceiptValidationResponse>(url);
150
+ return await enhancedFetch<ReceiptValidationResponse>(url, {
151
+ method: 'POST',
152
+ body: receiptBody,
153
+ });
150
154
  };
151
155
 
152
156
  /**
@@ -13,14 +13,16 @@ const {RNIapIosSk2} = NativeModules;
13
13
 
14
14
  type getItems = (skus: Sku[]) => Promise<ProductSk2[]>;
15
15
 
16
- type getAvailableItems = () => Promise<Purchase[]>;
16
+ type getAvailableItems = (
17
+ alsoPublishToEventListener?: boolean,
18
+ ) => Promise<Purchase[]>;
17
19
 
18
20
  export type BuyProduct = (
19
21
  sku: Sku,
20
22
  andDangerouslyFinishTransactionAutomaticallyIOS: boolean,
21
23
  applicationUsername: string | undefined,
22
24
  quantity: number,
23
- withOffer: PaymentDiscountSk2 | undefined,
25
+ withOffer: Record<keyof PaymentDiscountSk2, string> | undefined,
24
26
  ) => Promise<Purchase>;
25
27
 
26
28
  type clearTransaction = () => Promise<void>;
@@ -51,6 +53,7 @@ export interface IosModulePropsSk2 extends NativeModuleProps {
51
53
  finishTransaction: finishTransaction;
52
54
  getPendingTransactions: getPendingTransactions;
53
55
  presentCodeRedemptionSheet: presentCodeRedemptionSheet;
56
+ disable: () => Promise<null>;
54
57
  }
55
58
 
56
59
  /**