react-native-iap 10.1.0 → 10.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,6 @@ Read the [documentation](https://react-native-iap.dooboolab.com). See the [troub
19
19
  Please [fund the project](https://opencollective.com/react-native-iap) if you are willing the maintainers to make the repository sustainable.
20
20
 
21
21
  - [andresesfm](https://github.com/andresesfm)
22
- - [jeremybarbet](https://github.com/jeremybarbet)
23
22
 
24
23
  > The fund goes to maintainers.
25
24
 
@@ -390,7 +390,7 @@ class RNIapIos: RCTEventEmitter, SKRequestDelegate, SKPaymentTransactionObserver
390
390
  ) {
391
391
  requestReceiptData(withBlock: refresh) { [self] receiptData, error in
392
392
  if error == nil {
393
- resolve(receiptData?.base64EncodedString(options: []))
393
+ resolve(receiptData?.base64EncodedString(options: [.endLineWithCarriageReturn]))
394
394
  } else {
395
395
  reject(standardErrorCode(9), "Invalid receipt", nil)
396
396
  }
@@ -423,7 +423,7 @@ class RNIapIos: RCTEventEmitter, SKRequestDelegate, SKPaymentTransactionObserver
423
423
  "transactionId": item.transactionIdentifier,
424
424
  "productId": item.payment.productIdentifier,
425
425
  "quantity": "\(item.payment.quantity)",
426
- "transactionReceipt": receipt.base64EncodedString(options: [])
426
+ "transactionReceipt": receipt.base64EncodedString(options: [.endLineWithCarriageReturn])
427
427
  ]
428
428
 
429
429
  output.append(purchase)
@@ -907,7 +907,7 @@ class RNIapIos: RCTEventEmitter, SKRequestDelegate, SKPaymentTransactionObserver
907
907
  "transactionDate": transaction.transactionDate?.millisecondsSince1970String,
908
908
  "transactionId": transaction.transactionIdentifier,
909
909
  "productId": transaction.payment.productIdentifier,
910
- "transactionReceipt": receiptData?.base64EncodedString(options: [])
910
+ "transactionReceipt": receiptData?.base64EncodedString(options: [.endLineWithCarriageReturn])
911
911
  ]
912
912
 
913
913
  // originalTransaction is available for restore purchase and purchase of cancelled/expired subscriptions
@@ -63,7 +63,21 @@ const getNativeModule = () => {
63
63
  };
64
64
  /**
65
65
  * Init module for purchase flow. Required on Android. In ios it will check whether user canMakePayment.
66
- * @returns {Promise<boolean>}
66
+ * ## Usage
67
+
68
+ ```tsx
69
+ import React, {useEffect} from 'react';
70
+ import {View} from 'react-native';
71
+ import {initConnection} from 'react-native-iap';
72
+
73
+ const App = () => {
74
+ useEffect(() => {
75
+ void initConnection();
76
+ }, []);
77
+
78
+ return <View />;
79
+ };
80
+ ```
67
81
  */
68
82
 
69
83
 
@@ -71,7 +85,23 @@ exports.getNativeModule = getNativeModule;
71
85
 
72
86
  const initConnection = () => getNativeModule().initConnection();
73
87
  /**
74
- * End module for purchase flow.
88
+ * Disconnects from native SDK
89
+ * Usage
90
+ * ```tsx
91
+ import React, {useEffect} from 'react';
92
+ import {View} from 'react-native';
93
+ import {endConnection} from 'react-native-iap';
94
+
95
+ const App = () => {
96
+ useEffect(() => {
97
+ return () => {
98
+ void endConnection();
99
+ };
100
+ }, []);
101
+
102
+ return <View />;
103
+ };
104
+ ```
75
105
  * @returns {Promise<void>}
76
106
  */
77
107
 
@@ -90,8 +120,47 @@ exports.endConnection = endConnection;
90
120
  const flushFailedPurchasesCachedAsPendingAndroid = () => getAndroidModule().flushFailedPurchasesCachedAsPending();
91
121
  /**
92
122
  * Get a list of products (consumable and non-consumable items, but not subscriptions)
93
- * @param {string[]} skus The item skus
94
- * @returns {Promise<Product[]>}
123
+ ## Usage
124
+
125
+ ```ts
126
+ import React, {useState} from 'react';
127
+ import {Platform} from 'react-native';
128
+ import {getProducts, Product} from 'react-native-iap';
129
+
130
+ const skus = Platform.select({
131
+ ios: ['com.example.consumableIos'],
132
+ android: ['com.example.consumableAndroid'],
133
+ });
134
+
135
+ const App = () => {
136
+ const [products, setProducts] = useState<Product[]>([]);
137
+
138
+ const handleProducts = async () => {
139
+ const items = await getProducts({skus});
140
+
141
+ setProducts(items);
142
+ };
143
+
144
+ useEffect(() => {
145
+ void handleProducts();
146
+ }, []);
147
+
148
+ return (
149
+ <>
150
+ {products.map((product) => (
151
+ <Text key={product.productId}>{product.productId}</Text>
152
+ ))}
153
+ </>
154
+ );
155
+ };
156
+ ```
157
+
158
+ Just a few things to keep in mind:
159
+
160
+ - You can get your products in `componentDidMount`, `useEffect` or another appropriate area of your app.
161
+ - 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.
162
+ - 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.
163
+
95
164
  */
96
165
 
97
166
 
@@ -114,8 +183,24 @@ const getProducts = _ref => {
114
183
  };
115
184
  /**
116
185
  * Get a list of subscriptions
117
- * @param {string[]} skus The item skus
118
- * @returns {Promise<Subscription[]>}
186
+ * ## Usage
187
+
188
+ ```tsx
189
+ import React, {useCallback} from 'react';
190
+ import {View} from 'react-native';
191
+ import {getSubscriptions} from 'react-native-iap';
192
+
193
+ const App = () => {
194
+ const subscriptions = useCallback(
195
+ async () =>
196
+ await getSubscriptions(['com.example.product1', 'com.example.product2']),
197
+ [],
198
+ );
199
+
200
+ return <View />;
201
+ };
202
+ ```
203
+
119
204
  */
120
205
 
121
206
 
@@ -138,7 +223,26 @@ const getSubscriptions = _ref2 => {
138
223
  };
139
224
  /**
140
225
  * Gets an inventory of purchases made by the user regardless of consumption status
141
- * @returns {Promise<(ProductPurchase | SubscriptionPurchase)[]>}
226
+ * ## Usage
227
+
228
+ ```tsx
229
+ import React, {useCallback} from 'react';
230
+ import {View} from 'react-native';
231
+ import {getPurchaseHistory} from 'react-native-iap';
232
+
233
+ const App = () => {
234
+ const history = useCallback(
235
+ async () =>
236
+ await getPurchaseHistory([
237
+ 'com.example.product1',
238
+ 'com.example.product2',
239
+ ]),
240
+ [],
241
+ );
242
+
243
+ return <View />;
244
+ };
245
+ ```
142
246
  */
143
247
 
144
248
 
@@ -160,7 +264,81 @@ const getPurchaseHistory = () => (_reactNative.Platform.select({
160
264
  }) || (() => Promise.resolve([])))();
161
265
  /**
162
266
  * Get all purchases made by the user (either non-consumable, or haven't been consumed yet)
163
- * @returns {Promise<(ProductPurchase | SubscriptionPurchase)[]>}
267
+ * ## Usage
268
+
269
+ ```tsx
270
+ import React, {useCallback} from 'react';
271
+ import {View} from 'react-native';
272
+ import {getAvailablePurchases} from 'react-native-iap';
273
+
274
+ const App = () => {
275
+ const availablePurchases = useCallback(
276
+ async () => await getAvailablePurchases(),
277
+ [],
278
+ );
279
+
280
+ return <View />;
281
+ };
282
+ ```
283
+
284
+ ## Restoring purchases
285
+
286
+ You can use `getAvailablePurchases()` to do what's commonly understood as "restoring" purchases.
287
+
288
+ :::note
289
+ For debugging you may want to consume all items, you have then to iterate over the purchases returned by `getAvailablePurchases()`.
290
+ :::
291
+
292
+ :::warning
293
+ 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.
294
+ :::
295
+
296
+ ```tsx
297
+ import React from 'react';
298
+ import {Button} from 'react-native';
299
+ import {getAvailablePurchases,finishTransaction} from 'react-native-iap';
300
+
301
+ const App = () => {
302
+ handleRestore = async () => {
303
+ try {
304
+ const purchases = await getAvailablePurchases();
305
+ const newState = {premium: false, ads: true};
306
+ let titles = [];
307
+
308
+ await Promise.all(purchases.map(async purchase => {
309
+ switch (purchase.productId) {
310
+ case 'com.example.premium':
311
+ newState.premium = true;
312
+ titles.push('Premium Version');
313
+ break;
314
+
315
+ case 'com.example.no_ads':
316
+ newState.ads = false;
317
+ titles.push('No Ads');
318
+ break;
319
+
320
+ case 'com.example.coins100':
321
+ await finishTransaction(purchase.purchaseToken);
322
+ CoinStore.addCoins(100);
323
+ }
324
+ })
325
+
326
+ Alert.alert(
327
+ 'Restore Successful',
328
+ `You successfully restored the following purchases: ${titles.join(', ')}`,
329
+ );
330
+ } catch (error) {
331
+ console.warn(error);
332
+ Alert.alert(error.message);
333
+ }
334
+ };
335
+
336
+ return (
337
+ <Button title="Restore purchases" onPress={handleRestore} />
338
+ )
339
+ };
340
+ ```
341
+ *
164
342
  */
165
343
 
166
344
 
@@ -182,14 +360,70 @@ const getAvailablePurchases = () => (_reactNative.Platform.select({
182
360
  }) || (() => Promise.resolve([])))();
183
361
  /**
184
362
  * Request a purchase for product. This will be received in `PurchaseUpdatedListener`.
185
- * @param {string} sku The product's sku/ID
186
- * @param {string} [applicationUsername] The purchaser's user ID
187
- * @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.
188
- * @param {string} [obfuscatedAccountIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
189
- * @param {string} [obfuscatedProfileIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
190
- * @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
191
- * @param {boolean} [isOfferPersonalized] Defaults to false, Only for Android V5
192
- * @returns {Promise<ProductPurchase>}
363
+ * Request a purchase for a product (consumables or non-consumables).
364
+
365
+ The response will be received through the `PurchaseUpdatedListener`.
366
+
367
+ :::note
368
+ `andDangerouslyFinishTransactionAutomatically` defaults to false. We recommend
369
+ always keeping at false, and verifying the transaction receipts on the server-side.
370
+ :::
371
+
372
+ ## Signature
373
+
374
+ ```ts
375
+ requestPurchase(
376
+ The product's sku/ID
377
+ sku,
378
+
379
+
380
+ * You should set this to false and call finishTransaction manually when you have delivered the purchased goods to the user.
381
+ * @default false
382
+
383
+ andDangerouslyFinishTransactionAutomaticallyIOS = false,
384
+
385
+ /** Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
386
+ obfuscatedAccountIdAndroid,
387
+
388
+ Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
389
+ obfuscatedProfileIdAndroid,
390
+
391
+ The purchaser's user ID
392
+ applicationUsername,
393
+ ): Promise<ProductPurchase>;
394
+ ```
395
+
396
+ ## Usage
397
+
398
+ ```tsx
399
+ import React, {useCallback} from 'react';
400
+ import {Button} from 'react-native';
401
+ import {requestPurchase, Product, Sku, getProducts} from 'react-native-iap';
402
+
403
+ const App = () => {
404
+ const products = useCallback(
405
+ async () => getProducts(['com.example.product']),
406
+ [],
407
+ );
408
+
409
+ const handlePurchase = async (sku: Sku) => {
410
+ await requestPurchase({sku});
411
+ };
412
+
413
+ return (
414
+ <>
415
+ {products.map((product) => (
416
+ <Button
417
+ key={product.productId}
418
+ title="Buy product"
419
+ onPress={() => handlePurchase(product.productId)}
420
+ />
421
+ ))}
422
+ </>
423
+ );
424
+ };
425
+ ```
426
+
193
427
  */
194
428
 
195
429
 
@@ -236,15 +470,80 @@ const requestPurchase = _ref3 => {
236
470
  };
237
471
  /**
238
472
  * Request a purchase for product. This will be received in `PurchaseUpdatedListener`.
239
- * @param {string} [sku] The product's sku/ID
240
- * @param {string} [applicationUsername] The purchaser's user ID
241
- * @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.
242
- * @param {string} [purchaseTokenAndroid] purchaseToken that the user is upgrading or downgrading from (Android).
243
- * @param {ProrationModesAndroid} [prorationModeAndroid] UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, IMMEDIATE_WITH_TIME_PRORATION, IMMEDIATE_AND_CHARGE_PRORATED_PRICE, IMMEDIATE_WITHOUT_PRORATION, DEFERRED
244
- * @param {string} [obfuscatedAccountIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
245
- * @param {string} [obfuscatedProfileIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
246
- * @param {SubscriptionOffers[]} [subscriptionOffers] Array of SubscriptionOffers. Every sku must be paired with a corresponding offerToken
247
- * @returns {Promise<SubscriptionPurchase | null>} Promise resolves to null when using proratioModesAndroid=DEFERRED, and to a SubscriptionPurchase otherwise
473
+ * Request a purchase for a subscription.
474
+
475
+ The response will be received through the `PurchaseUpdatedListener`.
476
+
477
+ :::note
478
+ `andDangerouslyFinishTransactionAutomatically` defaults to false. We recommend
479
+ always keeping at false, and verifying the transaction receipts on the server-side.
480
+ :::
481
+
482
+ ## Signature
483
+
484
+ ```ts
485
+ requestSubscription(
486
+ The product's sku/ID
487
+ sku,
488
+
489
+
490
+ * You should set this to false and call finishTransaction manually when you have delivered the purchased goods to the user.
491
+ * @default false
492
+
493
+ andDangerouslyFinishTransactionAutomaticallyIOS = false,
494
+
495
+ purchaseToken that the user is upgrading or downgrading from (Android).
496
+ purchaseTokenAndroid,
497
+
498
+ UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, IMMEDIATE_WITH_TIME_PRORATION, IMMEDIATE_AND_CHARGE_PRORATED_PRICE, IMMEDIATE_WITHOUT_PRORATION, DEFERRED
499
+ prorationModeAndroid = -1,
500
+
501
+ /** Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
502
+ obfuscatedAccountIdAndroid,
503
+
504
+ Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
505
+ obfuscatedProfileIdAndroid,
506
+
507
+ The purchaser's user ID
508
+ applicationUsername,
509
+ ): Promise<SubscriptionPurchase>
510
+ ```
511
+
512
+ ## Usage
513
+
514
+ ```tsx
515
+ import React, {useCallback} from 'react';
516
+ import {Button} from 'react-native';
517
+ import {
518
+ requestSubscription,
519
+ Product,
520
+ Sku,
521
+ getSubscriptions,
522
+ } from 'react-native-iap';
523
+
524
+ const App = () => {
525
+ const subscriptions = useCallback(
526
+ async () => getSubscriptions(['com.example.subscription']),
527
+ [],
528
+ );
529
+
530
+ const handlePurchase = async (sku: Sku) => {
531
+ await requestSubscription({sku});
532
+ };
533
+
534
+ return (
535
+ <>
536
+ {subscriptions.map((subscription) => (
537
+ <Button
538
+ key={subscription.productId}
539
+ title="Buy subscription"
540
+ onPress={() => handlePurchase(subscription.productId)}
541
+ />
542
+ ))}
543
+ </>
544
+ );
545
+ };
546
+ ```
248
547
  */
249
548
 
250
549
 
@@ -314,10 +613,22 @@ const requestPurchaseWithQuantityIOS = _ref5 => {
314
613
  * Call this after you have persisted the purchased state to your server or local data in your app.
315
614
  * `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.**
316
615
  * Android: it will consume purchase for consumables and acknowledge purchase for non-consumables.
317
- * @param {object} purchase The purchase that you would like to finish.
318
- * @param {boolean} isConsumable Checks if purchase is consumable. Has effect on `android`.
319
- * @param {string} developerPayloadAndroid Android developerPayload.
320
- * @returns {Promise<string | void> }
616
+ *
617
+ ```tsx
618
+ import React from 'react';
619
+ import {Button} from 'react-native';
620
+ import {finishTransaction} from 'react-native-iap';
621
+
622
+ const App = () => {
623
+ const handlePurchase = async () => {
624
+ // ... handle the purchase request
625
+
626
+ const result = finishTransaction(purchase);
627
+ };
628
+
629
+ return <Button title="Buy product" onPress={handlePurchase} />;
630
+ };
631
+ ```
321
632
  */
322
633
 
323
634
 
@@ -495,7 +806,10 @@ const validateReceiptIos = async _ref10 => {
495
806
  }
496
807
 
497
808
  const url = isTest ? 'https://sandbox.itunes.apple.com/verifyReceipt' : 'https://buy.itunes.apple.com/verifyReceipt';
498
- return await (0, _internal.enhancedFetch)(url);
809
+ return await (0, _internal.enhancedFetch)(url, {
810
+ method: 'POST',
811
+ body: receiptBody
812
+ });
499
813
  };
500
814
  /**
501
815
  * Validate receipt for Android. NOTE: This method is here for debugging purposes only. Including