react-native-iap 11.0.0-alpha.7 → 11.0.0-rc.1

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 (65) hide show
  1. package/README.md +0 -1
  2. package/ios/IapSerializationUtils.swift +30 -0
  3. package/ios/RNIapIos.m +1 -10
  4. package/ios/RNIapIos.swift +18 -84
  5. package/ios/RNIapIosSk2.m +5 -0
  6. package/ios/RNIapIosSk2.swift +66 -52
  7. package/lib/commonjs/eventEmitter.js +4 -4
  8. package/lib/commonjs/eventEmitter.js.map +1 -1
  9. package/lib/commonjs/hooks/withIAPContext.js +1 -1
  10. package/lib/commonjs/hooks/withIAPContext.js.map +1 -1
  11. package/lib/commonjs/iap.js +398 -335
  12. package/lib/commonjs/iap.js.map +1 -1
  13. package/lib/commonjs/index.js +13 -0
  14. package/lib/commonjs/index.js.map +1 -1
  15. package/lib/commonjs/internal/platform.js +75 -2
  16. package/lib/commonjs/internal/platform.js.map +1 -1
  17. package/lib/commonjs/modules/amazon.js +28 -1
  18. package/lib/commonjs/modules/amazon.js.map +1 -1
  19. package/lib/commonjs/modules/android.js +73 -1
  20. package/lib/commonjs/modules/android.js.map +1 -1
  21. package/lib/commonjs/modules/ios.js +126 -0
  22. package/lib/commonjs/modules/ios.js.map +1 -1
  23. package/lib/commonjs/modules/iosSk2.js +47 -0
  24. package/lib/commonjs/modules/iosSk2.js.map +1 -1
  25. package/lib/commonjs/types/appleSk2.js +21 -1
  26. package/lib/commonjs/types/appleSk2.js.map +1 -1
  27. package/lib/module/eventEmitter.js +2 -2
  28. package/lib/module/eventEmitter.js.map +1 -1
  29. package/lib/module/hooks/withIAPContext.js +2 -2
  30. package/lib/module/hooks/withIAPContext.js.map +1 -1
  31. package/lib/module/iap.js +359 -267
  32. package/lib/module/iap.js.map +1 -1
  33. package/lib/module/index.js +1 -0
  34. package/lib/module/index.js.map +1 -1
  35. package/lib/module/internal/platform.js +48 -1
  36. package/lib/module/internal/platform.js.map +1 -1
  37. package/lib/module/modules/amazon.js +23 -0
  38. package/lib/module/modules/amazon.js.map +1 -1
  39. package/lib/module/modules/android.js +59 -1
  40. package/lib/module/modules/android.js.map +1 -1
  41. package/lib/module/modules/ios.js +102 -1
  42. package/lib/module/modules/ios.js.map +1 -1
  43. package/lib/module/modules/iosSk2.js +30 -1
  44. package/lib/module/modules/iosSk2.js.map +1 -1
  45. package/lib/module/types/appleSk2.js +17 -0
  46. package/lib/module/types/appleSk2.js.map +1 -1
  47. package/lib/typescript/iap.d.ts +347 -168
  48. package/lib/typescript/index.d.ts +1 -0
  49. package/lib/typescript/internal/platform.d.ts +9 -0
  50. package/lib/typescript/modules/amazon.d.ts +17 -0
  51. package/lib/typescript/modules/android.d.ts +38 -1
  52. package/lib/typescript/modules/ios.d.ts +57 -5
  53. package/lib/typescript/modules/iosSk2.d.ts +28 -7
  54. package/lib/typescript/types/appleSk2.d.ts +31 -0
  55. package/package.json +5 -2
  56. package/src/eventEmitter.ts +4 -3
  57. package/src/hooks/withIAPContext.tsx +2 -2
  58. package/src/iap.ts +402 -356
  59. package/src/index.ts +1 -0
  60. package/src/internal/platform.ts +77 -1
  61. package/src/modules/amazon.ts +29 -1
  62. package/src/modules/android.ts +83 -2
  63. package/src/modules/ios.ts +124 -13
  64. package/src/modules/iosSk2.ts +46 -15
  65. package/src/types/appleSk2.ts +58 -1
@@ -3,16 +3,50 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.validateReceiptIos = exports.validateReceiptAndroid = exports.validateReceiptAmazon = exports.setIosNativeModule = exports.setAndroidNativeModule = exports.requestSubscription = exports.requestPurchaseWithOfferIOS = exports.requestPurchase = exports.presentCodeRedemptionSheetIOS = exports.isIosStorekit2 = exports.initConnection = exports.getSubscriptions = exports.getReceiptIOS = exports.getPurchaseHistory = exports.getPromotedProductIOS = exports.getProducts = exports.getPendingPurchasesIOS = exports.getNativeModule = exports.getIosModule = exports.getInstallSourceAndroid = exports.getAvailablePurchases = exports.getAndroidModule = exports.flushFailedPurchasesCachedAsPendingAndroid = exports.finishTransaction = exports.endConnection = exports.deepLinkToSubscriptionsAndroid = exports.clearTransactionIOS = exports.clearProductsIOS = exports.buyPromotedProductIOS = exports.acknowledgePurchaseAndroid = void 0;
6
+ exports.IapIosSk2 = exports.IapIos = exports.IapAndroid = exports.IapAmazon = void 0;
7
+ Object.defineProperty(exports, "enableStorekit2", {
8
+ enumerable: true,
9
+ get: function () {
10
+ return _internal.enableStorekit2;
11
+ }
12
+ });
13
+ exports.initConnection = exports.getSubscriptions = exports.getPurchaseHistory = exports.getProducts = exports.getAvailablePurchases = exports.flushFailedPurchasesCachedAsPendingAndroid = exports.finishTransaction = exports.endConnection = void 0;
14
+ Object.defineProperty(exports, "isIosStorekit2", {
15
+ enumerable: true,
16
+ get: function () {
17
+ return _internal.isIosStorekit2;
18
+ }
19
+ });
20
+ exports.requestSubscription = exports.requestPurchase = void 0;
7
21
 
8
22
  var _reactNative = require("react-native");
9
23
 
24
+ var IapAmazon = _interopRequireWildcard(require("./modules/amazon"));
25
+
26
+ exports.IapAmazon = IapAmazon;
27
+
28
+ var IapAndroid = _interopRequireWildcard(require("./modules/android"));
29
+
30
+ exports.IapAndroid = IapAndroid;
31
+
32
+ var IapIos = _interopRequireWildcard(require("./modules/ios"));
33
+
34
+ exports.IapIos = IapIos;
35
+
36
+ var IapIosSk2 = _interopRequireWildcard(require("./modules/iosSk2"));
37
+
38
+ exports.IapIosSk2 = IapIosSk2;
39
+
10
40
  var _appleSk = require("./types/appleSk2");
11
41
 
12
42
  var _internal = require("./internal");
13
43
 
14
44
  var _types = require("./types");
15
45
 
46
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
47
+
48
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
49
+
16
50
  const {
17
51
  RNIapIos,
18
52
  RNIapIosSk2,
@@ -21,78 +55,51 @@ const {
21
55
  } = _reactNative.NativeModules;
22
56
  const ANDROID_ITEM_TYPE_SUBSCRIPTION = _types.ProductType.subs;
23
57
  const ANDROID_ITEM_TYPE_IAP = _types.ProductType.inapp;
58
+ /**
59
+ * Init module for purchase flow. Required on Android. In ios it will check whether user canMakePayment.
60
+ * ## Usage
24
61
 
25
- const getInstallSourceAndroid = () => {
26
- return RNIapModule ? _types.InstallSourceAndroid.GOOGLE_PLAY : _types.InstallSourceAndroid.AMAZON;
27
- };
28
-
29
- exports.getInstallSourceAndroid = getInstallSourceAndroid;
30
- let androidNativeModule = RNIapModule;
31
- let iosNativeModule = RNIapIosSk2;
32
-
33
- const isIosStorekit2 = () => iosNativeModule === RNIapIosSk2;
34
-
35
- exports.isIosStorekit2 = isIosStorekit2;
36
-
37
- const setAndroidNativeModule = nativeModule => {
38
- androidNativeModule = nativeModule;
39
- };
40
-
41
- exports.setAndroidNativeModule = setAndroidNativeModule;
42
-
43
- const setIosNativeModule = nativeModule => {
44
- iosNativeModule = nativeModule;
45
- };
46
-
47
- exports.setIosNativeModule = setIosNativeModule;
48
-
49
- const checkNativeAndroidAvailable = () => {
50
- if (!RNIapModule && !RNIapAmazonModule) {
51
- throw new Error('IAP_NOT_AVAILABLE');
52
- }
53
- };
54
-
55
- const getAndroidModule = () => {
56
- checkNativeAndroidAvailable();
57
- return androidNativeModule ? androidNativeModule : RNIapModule ? RNIapModule : RNIapAmazonModule;
58
- };
59
-
60
- exports.getAndroidModule = getAndroidModule;
61
-
62
- const checkNativeIOSAvailable = () => {
63
- if (!RNIapIos && !RNIapIosSk2) {
64
- throw new Error('IAP_NOT_AVAILABLE');
65
- }
66
- };
67
-
68
- const getIosModule = () => {
69
- checkNativeIOSAvailable();
70
- return iosNativeModule ? iosNativeModule : RNIapIosSk2 ? RNIapIosSk2 : RNIapIos;
71
- };
62
+ ```tsx
63
+ import React, {useEffect} from 'react';
64
+ import {View} from 'react-native';
65
+ import {initConnection} from 'react-native-iap';
72
66
 
73
- exports.getIosModule = getIosModule;
67
+ const App = () => {
68
+ useEffect(() => {
69
+ void initConnection();
70
+ }, []);
74
71
 
75
- const getNativeModule = () => {
76
- return _internal.isAndroid ? getAndroidModule() : getIosModule();
72
+ return <View />;
77
73
  };
78
- /**
79
- * Init module for purchase flow. Required on Android. In ios it will check whether user canMakePayment.
80
- * @returns {Promise<boolean>}
74
+ ```
81
75
  */
82
76
 
83
-
84
- exports.getNativeModule = getNativeModule;
85
-
86
- const initConnection = () => getNativeModule().initConnection();
77
+ const initConnection = () => (0, _internal.getNativeModule)().initConnection();
87
78
  /**
88
- * End module for purchase flow.
79
+ * Disconnects from native SDK
80
+ * Usage
81
+ * ```tsx
82
+ import React, {useEffect} from 'react';
83
+ import {View} from 'react-native';
84
+ import {endConnection} from 'react-native-iap';
85
+
86
+ const App = () => {
87
+ useEffect(() => {
88
+ return () => {
89
+ void endConnection();
90
+ };
91
+ }, []);
92
+
93
+ return <View />;
94
+ };
95
+ ```
89
96
  * @returns {Promise<void>}
90
97
  */
91
98
 
92
99
 
93
100
  exports.initConnection = initConnection;
94
101
 
95
- const endConnection = () => getNativeModule().endConnection();
102
+ const endConnection = () => (0, _internal.getNativeModule)().endConnection();
96
103
  /**
97
104
  * Consume all 'ghost' purchases (that is, pending payment that already failed but is still marked as pending in Play Store cache). Android only.
98
105
  * @returns {Promise<boolean>}
@@ -101,11 +108,50 @@ const endConnection = () => getNativeModule().endConnection();
101
108
 
102
109
  exports.endConnection = endConnection;
103
110
 
104
- const flushFailedPurchasesCachedAsPendingAndroid = () => getAndroidModule().flushFailedPurchasesCachedAsPending();
111
+ const flushFailedPurchasesCachedAsPendingAndroid = () => (0, _internal.getAndroidModule)().flushFailedPurchasesCachedAsPending();
105
112
  /**
106
113
  * Get a list of products (consumable and non-consumable items, but not subscriptions)
107
- * @param {string[]} skus The item skus
108
- * @returns {Promise<Product[]>}
114
+ ## Usage
115
+
116
+ ```ts
117
+ import React, {useState} from 'react';
118
+ import {Platform} from 'react-native';
119
+ import {getProducts, Product} from 'react-native-iap';
120
+
121
+ const skus = Platform.select({
122
+ ios: ['com.example.consumableIos'],
123
+ android: ['com.example.consumableAndroid'],
124
+ });
125
+
126
+ const App = () => {
127
+ const [products, setProducts] = useState<Product[]>([]);
128
+
129
+ const handleProducts = async () => {
130
+ const items = await getProducts({skus});
131
+
132
+ setProducts(items);
133
+ };
134
+
135
+ useEffect(() => {
136
+ void handleProducts();
137
+ }, []);
138
+
139
+ return (
140
+ <>
141
+ {products.map((product) => (
142
+ <Text key={product.productId}>{product.productId}</Text>
143
+ ))}
144
+ </>
145
+ );
146
+ };
147
+ ```
148
+
149
+ Just a few things to keep in mind:
150
+
151
+ - You can get your products in `componentDidMount`, `useEffect` or another appropriate area of your app.
152
+ - Since a user may start your app with a bad or no internet connection, preparing/getting the items more than once may be a good idea.
153
+ - If the user has no IAPs available when the app starts first, you may want to check again when the user enters your IAP store.
154
+
109
155
  */
110
156
 
111
157
 
@@ -119,7 +165,7 @@ const getProducts = _ref => {
119
165
  ios: async () => {
120
166
  let items;
121
167
 
122
- if (isIosStorekit2()) {
168
+ if ((0, _internal.isIosStorekit2)()) {
123
169
  items = (await RNIapIosSk2.getItems(skus)).map(_appleSk.productSk2Map);
124
170
  } else {
125
171
  items = await RNIapIos.getItems(skus);
@@ -128,15 +174,31 @@ const getProducts = _ref => {
128
174
  return items.filter(item => skus.includes(item.productId) && item.type === 'iap');
129
175
  },
130
176
  android: async () => {
131
- const products = await getAndroidModule().getItemsByType(ANDROID_ITEM_TYPE_IAP, skus);
177
+ const products = await (0, _internal.getAndroidModule)().getItemsByType(ANDROID_ITEM_TYPE_IAP, skus);
132
178
  return (0, _internal.fillProductsWithAdditionalData)(products);
133
179
  }
134
180
  }) || (() => Promise.reject(new Error('Unsupported Platform'))))();
135
181
  };
136
182
  /**
137
183
  * Get a list of subscriptions
138
- * @param {string[]} skus The item skus
139
- * @returns {Promise<Subscription[]>}
184
+ * ## Usage
185
+
186
+ ```tsx
187
+ import React, {useCallback} from 'react';
188
+ import {View} from 'react-native';
189
+ import {getSubscriptions} from 'react-native-iap';
190
+
191
+ const App = () => {
192
+ const subscriptions = useCallback(
193
+ async () =>
194
+ await getSubscriptions(['com.example.product1', 'com.example.product2']),
195
+ [],
196
+ );
197
+
198
+ return <View />;
199
+ };
200
+ ```
201
+
140
202
  */
141
203
 
142
204
 
@@ -150,7 +212,7 @@ const getSubscriptions = _ref2 => {
150
212
  ios: async () => {
151
213
  let items;
152
214
 
153
- if (isIosStorekit2()) {
215
+ if ((0, _internal.isIosStorekit2)()) {
154
216
  items = (await RNIapIosSk2.getItems(skus)).map(_appleSk.subscriptionSk2Map);
155
217
  } else {
156
218
  items = await RNIapIos.getItems(skus);
@@ -159,14 +221,33 @@ const getSubscriptions = _ref2 => {
159
221
  return items.filter(item => skus.includes(item.productId) && item.type === 'subs');
160
222
  },
161
223
  android: async () => {
162
- const subscriptions = await getAndroidModule().getItemsByType(ANDROID_ITEM_TYPE_SUBSCRIPTION, skus);
224
+ const subscriptions = await (0, _internal.getAndroidModule)().getItemsByType(ANDROID_ITEM_TYPE_SUBSCRIPTION, skus);
163
225
  return (0, _internal.fillProductsWithAdditionalData)(subscriptions);
164
226
  }
165
227
  }) || (() => Promise.reject(new Error('Unsupported Platform'))))();
166
228
  };
167
229
  /**
168
230
  * Gets an inventory of purchases made by the user regardless of consumption status
169
- * @returns {Promise<(ProductPurchase | SubscriptionPurchase)[]>}
231
+ * ## Usage
232
+
233
+ ```tsx
234
+ import React, {useCallback} from 'react';
235
+ import {View} from 'react-native';
236
+ import {getPurchaseHistory} from 'react-native-iap';
237
+
238
+ const App = () => {
239
+ const history = useCallback(
240
+ async () =>
241
+ await getPurchaseHistory([
242
+ 'com.example.product1',
243
+ 'com.example.product2',
244
+ ]),
245
+ [],
246
+ );
247
+
248
+ return <View />;
249
+ };
250
+ ```
170
251
  */
171
252
 
172
253
 
@@ -174,7 +255,7 @@ exports.getSubscriptions = getSubscriptions;
174
255
 
175
256
  const getPurchaseHistory = () => (_reactNative.Platform.select({
176
257
  ios: async () => {
177
- return getIosModule().getAvailableItems();
258
+ return (0, _internal.getIosModule)().getAvailableItems();
178
259
  },
179
260
  android: async () => {
180
261
  if (RNIapAmazonModule) {
@@ -188,7 +269,81 @@ const getPurchaseHistory = () => (_reactNative.Platform.select({
188
269
  }) || (() => Promise.resolve([])))();
189
270
  /**
190
271
  * Get all purchases made by the user (either non-consumable, or haven't been consumed yet)
191
- * @returns {Promise<(ProductPurchase | SubscriptionPurchase)[]>}
272
+ * ## Usage
273
+
274
+ ```tsx
275
+ import React, {useCallback} from 'react';
276
+ import {View} from 'react-native';
277
+ import {getAvailablePurchases} from 'react-native-iap';
278
+
279
+ const App = () => {
280
+ const availablePurchases = useCallback(
281
+ async () => await getAvailablePurchases(),
282
+ [],
283
+ );
284
+
285
+ return <View />;
286
+ };
287
+ ```
288
+
289
+ ## Restoring purchases
290
+
291
+ You can use `getAvailablePurchases()` to do what's commonly understood as "restoring" purchases.
292
+
293
+ :::note
294
+ For debugging you may want to consume all items, you have then to iterate over the purchases returned by `getAvailablePurchases()`.
295
+ :::
296
+
297
+ :::warning
298
+ Beware that if you consume an item without having recorded the purchase in your database the user may have paid for something without getting it delivered and you will have no way to recover the receipt to validate and restore their purchase.
299
+ :::
300
+
301
+ ```tsx
302
+ import React from 'react';
303
+ import {Button} from 'react-native';
304
+ import {getAvailablePurchases,finishTransaction} from 'react-native-iap';
305
+
306
+ const App = () => {
307
+ handleRestore = async () => {
308
+ try {
309
+ const purchases = await getAvailablePurchases();
310
+ const newState = {premium: false, ads: true};
311
+ let titles = [];
312
+
313
+ await Promise.all(purchases.map(async purchase => {
314
+ switch (purchase.productId) {
315
+ case 'com.example.premium':
316
+ newState.premium = true;
317
+ titles.push('Premium Version');
318
+ break;
319
+
320
+ case 'com.example.no_ads':
321
+ newState.ads = false;
322
+ titles.push('No Ads');
323
+ break;
324
+
325
+ case 'com.example.coins100':
326
+ await finishTransaction(purchase.purchaseToken);
327
+ CoinStore.addCoins(100);
328
+ }
329
+ })
330
+
331
+ Alert.alert(
332
+ 'Restore Successful',
333
+ `You successfully restored the following purchases: ${titles.join(', ')}`,
334
+ );
335
+ } catch (error) {
336
+ console.warn(error);
337
+ Alert.alert(error.message);
338
+ }
339
+ };
340
+
341
+ return (
342
+ <Button title="Restore purchases" onPress={handleRestore} />
343
+ )
344
+ };
345
+ ```
346
+ *
192
347
  */
193
348
 
194
349
 
@@ -196,7 +351,7 @@ exports.getPurchaseHistory = getPurchaseHistory;
196
351
 
197
352
  const getAvailablePurchases = () => (_reactNative.Platform.select({
198
353
  ios: async () => {
199
- return getIosModule().getAvailableItems();
354
+ return (0, _internal.getIosModule)().getAvailableItems();
200
355
  },
201
356
  android: async () => {
202
357
  if (RNIapAmazonModule) {
@@ -210,14 +365,70 @@ const getAvailablePurchases = () => (_reactNative.Platform.select({
210
365
  }) || (() => Promise.resolve([])))();
211
366
  /**
212
367
  * Request a purchase for product. This will be received in `PurchaseUpdatedListener`.
213
- * @param {string} sku The product's sku/ID
214
- * @param {string} [appAccountToken] UUID representing the purchaser
215
- * @param {boolean} [andDangerouslyFinishTransactionAutomaticallyIOS] You should set this to false 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.
216
- * @param {string} [obfuscatedAccountIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
217
- * @param {string} [obfuscatedProfileIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
218
- * @param {string[]} [skus] Product Ids to purchase. Note that this is only for Android. iOS only uses a single SKU. If not provided, it'll default to using [sku] for backward-compatibility
219
- * @param {boolean} [isOfferPersonalized] Defaults to false, Only for Android V5
220
- * @returns {Promise<ProductPurchase>}
368
+ * Request a purchase for a product (consumables or non-consumables).
369
+
370
+ The response will be received through the `PurchaseUpdatedListener`.
371
+
372
+ :::note
373
+ `andDangerouslyFinishTransactionAutomatically` defaults to false. We recommend
374
+ always keeping at false, and verifying the transaction receipts on the server-side.
375
+ :::
376
+
377
+ ## Signature
378
+
379
+ ```ts
380
+ requestPurchase(
381
+ The product's sku/ID
382
+ sku,
383
+
384
+
385
+ * You should set this to false and call finishTransaction manually when you have delivered the purchased goods to the user.
386
+ * @default false
387
+
388
+ andDangerouslyFinishTransactionAutomaticallyIOS = false,
389
+
390
+ /** Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
391
+ obfuscatedAccountIdAndroid,
392
+
393
+ Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
394
+ obfuscatedProfileIdAndroid,
395
+
396
+ The purchaser's user ID
397
+ applicationUsername,
398
+ ): Promise<ProductPurchase>;
399
+ ```
400
+
401
+ ## Usage
402
+
403
+ ```tsx
404
+ import React, {useCallback} from 'react';
405
+ import {Button} from 'react-native';
406
+ import {requestPurchase, Product, Sku, getProducts} from 'react-native-iap';
407
+
408
+ const App = () => {
409
+ const products = useCallback(
410
+ async () => getProducts(['com.example.product']),
411
+ [],
412
+ );
413
+
414
+ const handlePurchase = async (sku: Sku) => {
415
+ await requestPurchase({sku});
416
+ };
417
+
418
+ return (
419
+ <>
420
+ {products.map((product) => (
421
+ <Button
422
+ key={product.productId}
423
+ title="Buy product"
424
+ onPress={() => handlePurchase(product.productId)}
425
+ />
426
+ ))}
427
+ </>
428
+ );
429
+ };
430
+ ```
431
+
221
432
  */
222
433
 
223
434
 
@@ -247,7 +458,12 @@ const requestPurchase = _ref3 => {
247
458
  console.warn('You are dangerously allowing react-native-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.');
248
459
  }
249
460
 
250
- return getIosModule().buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, appAccountToken, quantity ?? -1, withOffer);
461
+ if ((0, _internal.isIosStorekit2)()) {
462
+ const offer = (0, _appleSk.offerSk2Map)(withOffer);
463
+ return RNIapIosSk2.buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, appAccountToken, quantity ?? -1, offer);
464
+ } else {
465
+ return RNIapIos.buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, appAccountToken, quantity ?? -1, withOffer);
466
+ }
251
467
  },
252
468
  android: async () => {
253
469
  if (_internal.isAmazon) {
@@ -261,22 +477,87 @@ const requestPurchase = _ref3 => {
261
477
  return Promise.reject(new Error('skus is required for Android purchase'));
262
478
  }
263
479
 
264
- return getAndroidModule().buyItemByType(ANDROID_ITEM_TYPE_IAP, skus !== null && skus !== void 0 && skus.length ? skus : [sku], undefined, -1, obfuscatedAccountIdAndroid, obfuscatedProfileIdAndroid, [], isOfferPersonalized ?? false);
480
+ return (0, _internal.getAndroidModule)().buyItemByType(ANDROID_ITEM_TYPE_IAP, skus !== null && skus !== void 0 && skus.length ? skus : [sku], undefined, -1, obfuscatedAccountIdAndroid, obfuscatedProfileIdAndroid, [], isOfferPersonalized ?? false);
265
481
  }
266
482
  }
267
483
  }) || Promise.resolve)();
268
484
  };
269
485
  /**
270
486
  * Request a purchase for product. This will be received in `PurchaseUpdatedListener`.
271
- * @param {string} [sku] The product's sku/ID
272
- * @param {string} [appAccountToken] The purchaser's user ID
273
- * @param {boolean} [andDangerouslyFinishTransactionAutomaticallyIOS] You should set this to false 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.
274
- * @param {string} [purchaseTokenAndroid] purchaseToken that the user is upgrading or downgrading from (Android).
275
- * @param {ProrationModesAndroid} [prorationModeAndroid] UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, IMMEDIATE_WITH_TIME_PRORATION, IMMEDIATE_AND_CHARGE_PRORATED_PRICE, IMMEDIATE_WITHOUT_PRORATION, DEFERRED
276
- * @param {string} [obfuscatedAccountIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
277
- * @param {string} [obfuscatedProfileIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
278
- * @param {SubscriptionOffers[]} [subscriptionOffers] Array of SubscriptionOffers. Every sku must be paired with a corresponding offerToken
279
- * @returns {Promise<SubscriptionPurchase | null>} Promise resolves to null when using proratioModesAndroid=DEFERRED, and to a SubscriptionPurchase otherwise
487
+ * Request a purchase for a subscription.
488
+
489
+ The response will be received through the `PurchaseUpdatedListener`.
490
+
491
+ :::note
492
+ `andDangerouslyFinishTransactionAutomatically` defaults to false. We recommend
493
+ always keeping at false, and verifying the transaction receipts on the server-side.
494
+ :::
495
+
496
+ ## Signature
497
+
498
+ ```ts
499
+ requestSubscription(
500
+ The product's sku/ID
501
+ sku,
502
+
503
+
504
+ * You should set this to false and call finishTransaction manually when you have delivered the purchased goods to the user.
505
+ * @default false
506
+
507
+ andDangerouslyFinishTransactionAutomaticallyIOS = false,
508
+
509
+ purchaseToken that the user is upgrading or downgrading from (Android).
510
+ purchaseTokenAndroid,
511
+
512
+ UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, IMMEDIATE_WITH_TIME_PRORATION, IMMEDIATE_AND_CHARGE_PRORATED_PRICE, IMMEDIATE_WITHOUT_PRORATION, DEFERRED
513
+ prorationModeAndroid = -1,
514
+
515
+ /** Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
516
+ obfuscatedAccountIdAndroid,
517
+
518
+ Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
519
+ obfuscatedProfileIdAndroid,
520
+
521
+ The purchaser's user ID
522
+ applicationUsername,
523
+ ): Promise<SubscriptionPurchase>
524
+ ```
525
+
526
+ ## Usage
527
+
528
+ ```tsx
529
+ import React, {useCallback} from 'react';
530
+ import {Button} from 'react-native';
531
+ import {
532
+ requestSubscription,
533
+ Product,
534
+ Sku,
535
+ getSubscriptions,
536
+ } from 'react-native-iap';
537
+
538
+ const App = () => {
539
+ const subscriptions = useCallback(
540
+ async () => getSubscriptions(['com.example.subscription']),
541
+ [],
542
+ );
543
+
544
+ const handlePurchase = async (sku: Sku) => {
545
+ await requestSubscription({sku});
546
+ };
547
+
548
+ return (
549
+ <>
550
+ {subscriptions.map((subscription) => (
551
+ <Button
552
+ key={subscription.productId}
553
+ title="Buy subscription"
554
+ onPress={() => handlePurchase(subscription.productId)}
555
+ />
556
+ ))}
557
+ </>
558
+ );
559
+ };
560
+ ```
280
561
  */
281
562
 
282
563
 
@@ -308,7 +589,12 @@ const requestSubscription = _ref4 => {
308
589
  console.warn('You are dangerously allowing react-native-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.');
309
590
  }
310
591
 
311
- return getIosModule().buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, appAccountToken, quantity ?? -1, withOffer);
592
+ if ((0, _internal.isIosStorekit2)()) {
593
+ const offer = (0, _appleSk.offerSk2Map)(withOffer);
594
+ return RNIapIosSk2.buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, appAccountToken, quantity ?? -1, offer);
595
+ } else {
596
+ return RNIapIos.buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, appAccountToken, quantity ?? -1, withOffer);
597
+ }
312
598
  },
313
599
  android: async () => {
314
600
  if (_internal.isAmazon) {
@@ -334,10 +620,22 @@ const requestSubscription = _ref4 => {
334
620
  * Call this after you have persisted the purchased state to your server or local data in your app.
335
621
  * `react-native-iap` will continue to deliver the purchase updated events with the successful purchase until you finish the transaction. **Even after the app has relaunched.**
336
622
  * Android: it will consume purchase for consumables and acknowledge purchase for non-consumables.
337
- * @param {object} purchase The purchase that you would like to finish.
338
- * @param {boolean} isConsumable Checks if purchase is consumable. Has effect on `android`.
339
- * @param {string} developerPayloadAndroid Android developerPayload.
340
- * @returns {Promise<string | void> }
623
+ *
624
+ ```tsx
625
+ import React from 'react';
626
+ import {Button} from 'react-native';
627
+ import {finishTransaction} from 'react-native-iap';
628
+
629
+ const App = () => {
630
+ const handlePurchase = async () => {
631
+ // ... handle the purchase request
632
+
633
+ const result = finishTransaction(purchase);
634
+ };
635
+
636
+ return <Button title="Buy product" onPress={handlePurchase} />;
637
+ };
638
+ ```
341
639
  */
342
640
 
343
641
 
@@ -357,14 +655,14 @@ const finishTransaction = _ref5 => {
357
655
  return Promise.reject(new Error('transactionId required to finish iOS transaction'));
358
656
  }
359
657
 
360
- return getIosModule().finishTransaction(transactionId);
658
+ return (0, _internal.getIosModule)().finishTransaction(transactionId);
361
659
  },
362
660
  android: async () => {
363
661
  if (purchase !== null && purchase !== void 0 && purchase.purchaseToken) {
364
662
  if (isConsumable) {
365
- return getAndroidModule().consumeProduct(purchase.purchaseToken, developerPayloadAndroid);
663
+ return (0, _internal.getAndroidModule)().consumeProduct(purchase.purchaseToken, developerPayloadAndroid);
366
664
  } else if (purchase.userIdAmazon || !purchase.isAcknowledgedAndroid && purchase.purchaseStateAndroid === _types.PurchaseStateAndroid.PURCHASED) {
367
- return getAndroidModule().acknowledgePurchase(purchase.purchaseToken, developerPayloadAndroid);
665
+ return (0, _internal.getAndroidModule)().acknowledgePurchase(purchase.purchaseToken, developerPayloadAndroid);
368
666
  } else {
369
667
  return Promise.reject(new Error('purchase is not suitable to be purchased'));
370
668
  }
@@ -374,241 +672,6 @@ const finishTransaction = _ref5 => {
374
672
  }
375
673
  }) || (() => Promise.reject(new Error('Unsupported Platform'))))();
376
674
  };
377
- /**
378
- * Clear Transaction (iOS only)
379
- * Finish remaining transactions. Related to issue #257 and #801
380
- * link : https://github.com/dooboolab/react-native-iap/issues/257
381
- * https://github.com/dooboolab/react-native-iap/issues/801
382
- * @returns {Promise<void>}
383
- */
384
-
385
675
 
386
676
  exports.finishTransaction = finishTransaction;
387
-
388
- const clearTransactionIOS = () => getIosModule().clearTransaction();
389
- /**
390
- * Clear valid Products (iOS only)
391
- * Remove all products which are validated by Apple server.
392
- * @returns {void}
393
- */
394
-
395
-
396
- exports.clearTransactionIOS = clearTransactionIOS;
397
-
398
- const clearProductsIOS = () => getIosModule().clearProducts();
399
- /**
400
- * Acknowledge a product (on Android.) No-op on iOS.
401
- * @param {string} token The product's token (on Android)
402
- * @returns {Promise<PurchaseResult | void>}
403
- */
404
-
405
-
406
- exports.clearProductsIOS = clearProductsIOS;
407
-
408
- const acknowledgePurchaseAndroid = _ref6 => {
409
- let {
410
- token,
411
- developerPayload
412
- } = _ref6;
413
- return getAndroidModule().acknowledgePurchase(token, developerPayload);
414
- };
415
- /**
416
- * Deep link to subscriptions screen on Android. No-op on iOS.
417
- * @param {string} sku The product's SKU (on Android)
418
- * @returns {Promise<void>}
419
- */
420
-
421
-
422
- exports.acknowledgePurchaseAndroid = acknowledgePurchaseAndroid;
423
-
424
- const deepLinkToSubscriptionsAndroid = async _ref7 => {
425
- let {
426
- sku
427
- } = _ref7;
428
- checkNativeAndroidAvailable();
429
- return _reactNative.Linking.openURL(`https://play.google.com/store/account/subscriptions?package=${await RNIapModule.getPackageName()}&sku=${sku}`);
430
- };
431
- /**
432
- * Should Add Store Payment (iOS only)
433
- * Indicates the the App Store purchase should continue from the app instead of the App Store.
434
- * @returns {Promise<Product | null>} promoted product
435
- */
436
-
437
-
438
- exports.deepLinkToSubscriptionsAndroid = deepLinkToSubscriptionsAndroid;
439
-
440
- const getPromotedProductIOS = () => {
441
- if (!isIosStorekit2) {
442
- return getIosModule().promotedProduct();
443
- } else {
444
- return Promise.reject('Only available on SK1');
445
- }
446
- };
447
- /**
448
- * Buy the currently selected promoted product (iOS only)
449
- * Initiates the payment process for a promoted product. Should only be called in response to the `iap-promoted-product` event.
450
- * @returns {Promise<void>}
451
- */
452
-
453
-
454
- exports.getPromotedProductIOS = getPromotedProductIOS;
455
-
456
- const buyPromotedProductIOS = () => getIosModule().buyPromotedProduct();
457
-
458
- exports.buyPromotedProductIOS = buyPromotedProductIOS;
459
- const TEST_RECEIPT = 21007;
460
-
461
- const requestAgnosticReceiptValidationIos = async receiptBody => {
462
- const response = await (0, _internal.enhancedFetch)('https://buy.itunes.apple.com/verifyReceipt', {
463
- method: 'POST',
464
- body: receiptBody
465
- }); // Best practice is to check for test receipt and check sandbox instead
466
- // https://developer.apple.com/documentation/appstorereceipts/verifyreceipt
467
-
468
- if (response && response.status === TEST_RECEIPT) {
469
- const testResponse = await (0, _internal.enhancedFetch)('https://sandbox.itunes.apple.com/verifyReceipt', {
470
- method: 'POST',
471
- body: receiptBody
472
- });
473
- return testResponse;
474
- }
475
-
476
- return response;
477
- };
478
- /**
479
- * Buy products or subscriptions with offers (iOS only)
480
- *
481
- * Runs the payment process with some info you must fetch
482
- * from your server.
483
- * @param {string} sku The product identifier
484
- * @param {string} forUser An user identifier on you system
485
- * @param {Apple.PaymentDiscount} withOffer The offer information
486
- * @param {string} withOffer.identifier The offer identifier
487
- * @param {string} withOffer.keyIdentifier Key identifier that it uses to generate the signature
488
- * @param {string} withOffer.nonce An UUID returned from the server
489
- * @param {string} withOffer.signature The actual signature returned from the server
490
- * @param {number} withOffer.timestamp The timestamp of the signature
491
- * @returns {Promise<void>}
492
- */
493
-
494
-
495
- const requestPurchaseWithOfferIOS = _ref8 => {
496
- let {
497
- sku,
498
- forUser,
499
- withOffer
500
- } = _ref8;
501
- return getIosModule().buyProductWithOffer(sku, forUser, withOffer);
502
- };
503
- /**
504
- * Validate receipt for iOS.
505
- * @param {object} receiptBody the receipt body to send to apple server.
506
- * @param {boolean} isTest whether this is in test environment which is sandbox.
507
- * @returns {Promise<Apple.ReceiptValidationResponse | false>}
508
- */
509
-
510
-
511
- exports.requestPurchaseWithOfferIOS = requestPurchaseWithOfferIOS;
512
-
513
- const validateReceiptIos = async _ref9 => {
514
- let {
515
- receiptBody,
516
- isTest
517
- } = _ref9;
518
-
519
- if (isTest == null) {
520
- return await requestAgnosticReceiptValidationIos(receiptBody);
521
- }
522
-
523
- const url = isTest ? 'https://sandbox.itunes.apple.com/verifyReceipt' : 'https://buy.itunes.apple.com/verifyReceipt';
524
- return await (0, _internal.enhancedFetch)(url);
525
- };
526
- /**
527
- * Validate receipt for Android. NOTE: This method is here for debugging purposes only. Including
528
- * your access token in the binary you ship to users is potentially dangerous.
529
- * Use server side validation instead for your production builds
530
- * @param {string} packageName package name of your app.
531
- * @param {string} productId product id for your in app product.
532
- * @param {string} productToken token for your purchase.
533
- * @param {string} accessToken accessToken from googleApis.
534
- * @param {boolean} isSub whether this is subscription or inapp. `true` for subscription.
535
- * @returns {Promise<object>}
536
- */
537
-
538
-
539
- exports.validateReceiptIos = validateReceiptIos;
540
-
541
- const validateReceiptAndroid = async _ref10 => {
542
- let {
543
- packageName,
544
- productId,
545
- productToken,
546
- accessToken,
547
- isSub
548
- } = _ref10;
549
- const type = isSub ? 'subscriptions' : 'products';
550
- const url = 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications' + `/${packageName}/purchases/${type}/${productId}` + `/tokens/${productToken}?access_token=${accessToken}`;
551
- return await (0, _internal.enhancedFetch)(url);
552
- };
553
- /**
554
- * Validate receipt for Amazon. NOTE: This method is here for debugging purposes only. Including
555
- * your developer secret in the binary you ship to users is potentially dangerous.
556
- * Use server side validation instead for your production builds
557
- * @param {string} developerSecret: from the Amazon developer console.
558
- * @param {string} userId who purchased the item.
559
- * @param {string} receiptId long obfuscated string returned when purchasing the item
560
- * @param {boolean} useSandbox Defaults to true, use sandbox environment or production.
561
- * @returns {Promise<object>}
562
- */
563
-
564
-
565
- exports.validateReceiptAndroid = validateReceiptAndroid;
566
-
567
- const validateReceiptAmazon = async _ref11 => {
568
- let {
569
- developerSecret,
570
- userId,
571
- receiptId,
572
- useSandbox = true
573
- } = _ref11;
574
- const sandBoxUrl = useSandbox ? 'sandbox/' : '';
575
- const url = `https://appstore-sdk.amazon.com/${sandBoxUrl}version/1.0/verifyReceiptId/developer/${developerSecret}/user/${userId}/receiptId/${receiptId}`;
576
- return await (0, _internal.enhancedFetch)(url);
577
- };
578
- /**
579
- * Get the current receipt base64 encoded in IOS.
580
- * @param {forceRefresh?:boolean}
581
- * @returns {Promise<ProductPurchase[]>}
582
- */
583
-
584
-
585
- exports.validateReceiptAmazon = validateReceiptAmazon;
586
-
587
- const getPendingPurchasesIOS = async () => getIosModule().getPendingTransactions();
588
- /**
589
- * Get the current receipt base64 encoded in IOS.
590
- * @param {forceRefresh?:boolean}
591
- * @returns {Promise<string>}
592
- */
593
-
594
-
595
- exports.getPendingPurchasesIOS = getPendingPurchasesIOS;
596
-
597
- const getReceiptIOS = async _ref12 => {
598
- let {
599
- forceRefresh
600
- } = _ref12;
601
- return getIosModule().requestReceipt(forceRefresh ?? false);
602
- };
603
- /**
604
- * Launches a modal to register the redeem offer code in IOS.
605
- * @returns {Promise<null>}
606
- */
607
-
608
-
609
- exports.getReceiptIOS = getReceiptIOS;
610
-
611
- const presentCodeRedemptionSheetIOS = async () => getIosModule().presentCodeRedemptionSheet();
612
-
613
- exports.presentCodeRedemptionSheetIOS = presentCodeRedemptionSheetIOS;
614
677
  //# sourceMappingURL=iap.js.map