react-native-iap 7.3.0 → 7.5.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  ## Changelogs
2
2
 
3
+ # 7.5.1
4
+
5
+ - Refresh SkuDetails (#1566)
6
+ - fix: NativeEventEmitter warnings since ReactNative 0.65 (#1544)
7
+ - Using TCK Tested JDK builds of OpenJDK (#1525)
8
+ - Add missing types for finishTransaction within useIAP() (#1533)
9
+
10
+ # 7.5.0
11
+
12
+ ### Bugfix
13
+
14
+ - Fix canceled purchase dangling [#1504](https://github.com/dooboolab/react-native-iap/pull/1504)
15
+
16
+ ### Dependencies
17
+
18
+ - Set default `androidX` version [#1505](https://github.com/dooboolab/react-native-iap/pull/1505)
19
+ - Update packages [#1506](https://github.com/dooboolab/react-native-iap/pull/1506)
20
+
21
+ # 7.4.1
22
+
23
+ - [iOS] Add `quantityIOS` in purchase data [#1476](https://github.com/dooboolab/react-native-iap/pull/1476)
24
+
25
+ # 7.4.0
26
+
27
+ - Now using React's Context to manage IAP state
28
+ - Introduce `withIAPContext` HOC ([how to use](docs/docs/usage_instructions/using_hooks.md))
29
+
3
30
  # 7.3.0
4
31
 
5
32
  _Breaking Change_:Amazon's receipt was incorrectly being put in `originalJson` it now matches the other platforms: `transactionReceipt` [#1461](https://github.com/dooboolab/react-native-iap/pull/1461)
package/README.md CHANGED
@@ -1,12 +1,13 @@
1
- ![image](https://user-images.githubusercontent.com/27461460/75094417-20321b00-55ce-11ea-8de7-a1df42a4b7df.png)
2
- ================
1
+ # ![image](https://user-images.githubusercontent.com/27461460/75094417-20321b00-55ce-11ea-8de7-a1df42a4b7df.png)
2
+
3
3
  [![Version](http://img.shields.io/npm/v/react-native-iap.svg?style=flat-square)](https://npmjs.org/package/react-native-iap)
4
+ [![Next](https://img.shields.io/npm/v/react-native-iap/next.svg?style=flat-square)](https://npmjs.org/package/react-native-iap)
4
5
  [![Download](http://img.shields.io/npm/dm/react-native-iap.svg?style=flat-square)](https://npmjs.org/package/react-native-iap)
5
6
  [![Build Status](https://travis-ci.com/dooboolab/react-native-iap.svg?branch=master)](https://travis-ci.com/dooboolab/react-native-iap)
6
7
  [![CI](https://github.com/dooboolab/react-native-iap/actions/workflows/ci.yml/badge.svg)](https://github.com/dooboolab/react-native-iap/actions/workflows/ci.yml)
7
8
  [![document](https://github.com/dooboolab/react-native-iap/actions/workflows/deploy-document.yml/badge.svg)](https://github.com/dooboolab/react-native-iap/actions/workflows/deploy-document.yml)
8
9
  [![License](https://img.shields.io/npm/l/react-native-iap.svg)](https://npmjs.org/package/react-native-iap)
9
- [![Vulnerabilites](https://img.shields.io/snyk/vulnerabilities/github/dooboolab/react-native-iap.svg)](https://github.com/dooboolab/react-native-iap)
10
+ [![Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/dooboolab/react-native-iap.svg)](https://github.com/dooboolab/react-native-iap)
10
11
  [![Issue Opened](https://img.shields.io/opencollective/all/react-native-iap.svg)](https://opencollective.com/react-native-iap#backers)
11
12
  [![Issue Opened](https://img.shields.io/github/issues/dooboolab/react-native-iap.svg)](https://github.com/dooboolab/react-native-iap/issues)
12
13
  [![Issue Closed](https://img.shields.io/github/issues-closed/dooboolab/react-native-iap.svg)](https://github.com/dooboolab/react-native-iap/issues?q=is%3Aissue+is%3Aclosed)
@@ -20,10 +21,17 @@ Published in [website](https://react-native-iap.dooboolab.com).
20
21
 
21
22
  ## Announcement
22
23
 
23
- React Native IAP hook is out. You can see [medium post](https://medium.com/dooboolab/announcing-react-native-iap-hooks-96c7ffd3f19a) on how to use it.
24
+ - Version `8.0.0` is currently in release candidate. The module is completely rewritten with `Kotlin` and `Swift` for maintenenance issue by [andresesfm](https://github.com/andresesfm) 🔆. You may install this for early preview.
25
+
26
+ ```
27
+ yarn add react-native-iap@next
28
+ ```
24
29
 
25
- The `react-native-iap` module hasn't been maintained well recently. We are thinking of participating again and make the module healthier. Please refer to [2021 Maintenance plan](https://github.com/dooboolab/react-native-iap/issues/1241) and share with us how you or your organization is using it. Happy new year 🎉
26
- - The sample code is out in [Sponsor page](https://github.com/hyochan/dooboolab.com/blob/master/src/components/pages/Sponsor.tsx) in [dooboolab.com](https://github.com/hyochan/dooboolab.com) repository which sadly is rejected by Apple because of lacking product features. I will work on another example project to support this module. More information in [#1241 commment](https://github.com/dooboolab/react-native-iap/issues/1241#issuecomment-798540785).
30
+ - React Native IAP hook is out. You can see [medium post](https://medium.com/dooboolab/announcing-react-native-iap-hooks-96c7ffd3f19a) on how to use it.
31
+
32
+ - The `react-native-iap` module hasn't been maintained well recently. We are thinking of participating again and make the module healthier. Please refer to [2021 Maintenance plan](https://github.com/dooboolab/react-native-iap/issues/1241) and share with us how you or your organization is using it. Happy new year 🎉
33
+
34
+ - The sample code is out in [Sponsor page](https://github.com/hyochan/dooboolab.com/blob/master/src/components/pages/Sponsor.tsx) in [dooboolab.com](https://github.com/hyochan/dooboolab.com) repository which sadly is rejected by Apple because of lacking product features. I will work on another example project to support this module. More information in [#1241 commment](https://github.com/dooboolab/react-native-iap/issues/1241#issuecomment-798540785).
27
35
 
28
36
  ## Introduction
29
37
 
@@ -35,26 +43,28 @@ Also, implementing the client side is only one side of the coin, you'll have to
35
43
  If you're looking for a module going further than react-native-iap, we recommend using [react-native-iaphub](https://github.com/iaphub/react-native-iaphub) which is taking care of everything from the client side to the server side.
36
44
 
37
45
  ⚠️ Most of users experiencing issues are caused by:
38
- - A device simulator, use a real device for testing!
39
- - The sandbox environment of the project not being configured properly ([Configure android sandbox](https://www.iaphub.com/docs/set-up-android/configure-sandbox-testing), [Configure ios sandbox](https://www.iaphub.com/docs/set-up-ios/configure-sandbox-testing/))
40
- - An incorrect usage of the library
41
46
 
47
+ - A device simulator, use a real device for testing!
48
+ - The sandbox environment of the project not being configured properly ([Configure android sandbox](https://www.iaphub.com/docs/set-up-android/configure-sandbox-testing), [Configure ios sandbox](https://www.iaphub.com/docs/set-up-ios/configure-sandbox-testing/))
49
+ - An incorrect usage of the library
50
+
51
+ ## Demo
42
52
 
43
- Demo
44
- ----------
45
- >
46
53
  > ![demo.gif](https://user-images.githubusercontent.com/27461460/52619625-87aa8a80-2ee5-11e9-9aee-6691c34408f3.gif)
47
54
 
48
55
  <!-- Inline anchors -->
56
+
49
57
  [a-acknowledge-purchase-android]: #finishing-a-purchase
50
58
  [a-migration-guide]: #migration-guide
51
59
  [a-purchase-flow]: #new-purchase-flow
52
60
 
53
61
  <!-- Official Blog -->
62
+
54
63
  [blog-config-steps]: https://medium.com/p/121622d26b67
55
64
  [blog-v3-note]: https://medium.com/p/1259e0b0c017
56
65
 
57
66
  <!-- Internals -->
67
+
58
68
  [contribute]: https://github.com/dooboolab/react-native-iap/blob/master/CONTRIBUTING.md
59
69
  [example]: https://github.com/dooboolab/react-native-iap/tree/master/IapExample
60
70
  [issue-126-c1]: https://github.com/dooboolab/react-native-iap/issues/126#issuecomment-439084872
@@ -72,8 +82,9 @@ Demo
72
82
  [readme-deprecated]: https://github.com/dooboolab/react-native-iap/blob/master/README_DEPRECATED.md
73
83
 
74
84
  <!-- Externals -->
75
- [android-acknowledge-purchase]: https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#acknowledgePurchase(com.android.billingclient.api.AcknowledgePurchaseParams,%20com.android.billingclient.api.AcknowledgePurchaseResponseListener) "BillingClient#acknowledgePurchase()"
76
- [android-end-connection]: https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#endConnection() "BillingClient#endConnection()"
85
+
86
+ [android-acknowledge-purchase]: https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#acknowledgePurchase(com.android.billingclient.api.AcknowledgePurchaseParams,%20com.android.billingclient.api.AcknowledgePurchaseResponseListener) 'BillingClient#acknowledgePurchase()'
87
+ [android-end-connection]: https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#endConnection() 'BillingClient#endConnection()'
77
88
  [android-iap-validation-guide]: https://developer.android.com/google/play/billing/billing_library_overview
78
89
  [android-migrate-androidx]: https://developer.android.com/jetpack/androidx/migrate
79
90
  [android-sku-details]: https://developer.android.com/reference/com/android/billingclient/api/SkuDetails
@@ -85,76 +96,87 @@ Demo
85
96
  [stackoverflow-android-iap-validation]: https://stackoverflow.com/questions/35127086
86
97
  [android-access-token-example-repo]: https://github.com/Bang9/android-get-access-token-example
87
98
 
88
- Quick News
89
- ----------
99
+ ## Quick News
100
+
90
101
  - We had hard time supporting `react-native-iap` issues that did not provide working codes or any other examples. Therefore, we've decided to make an `example` app called [DoobooIAP](https://github.com/hyochan/DoobooIAP), which will contain all the features of `IAP`'s and willing to continuously improve to support real-life examples. [@Bang9](http://github.com/bang9) who had been helping many others for `react-native-iap`, is willing to support this repo so he will grant $300 of our income in `opencollective` as described in [#855](https://github.com/dooboolab/react-native-iap/issues/855) :tada:.
91
102
  - `react-native-iap@4.0.8` ~ `react-native-iap@4.1.0` is incompatible with `react-native <0.61`. This is fixed in `react-native-iap@4.1.1` and above.
92
103
  - `react-native-iap@4.0.0` has been released. You can see [#716](https://github.com/dooboolab/react-native-iap/pull/716) for updates.
93
- - In the past, `react-native-iap@^3.*` has been updated very prompty for migration issues.
94
- Don't get suprised too much on why it is bumping up version so quickly these days.
104
+ - In the past, `react-native-iap@^3.*` has been updated very promptly for migration issues.
105
+ Don't get surprised too much on why it is bumping up version so quickly these days.
95
106
  1. Migrated to new `AndroidX` APIs.
96
107
  2. Migrated to new `Android` billing client which is `> 2.0.0`.
97
108
  - [`acknowledgePurchase()`][android-acknowledge-purchase] has been added since `3.2.0` which is very important.
98
109
  3. New [Purchase Flow][a-purchase-flow]
99
- 4. More is comming in `iOS 13`.
110
+ 4. More is coming in `iOS 13`.
111
+
112
+ ## Breaking Changes
100
113
 
101
- Breaking Changes
102
- ----------------
114
+ [7.4.0]
115
+
116
+ - Now using React's Context to manage IAP state
117
+ - Introduce `withIAPContext` HOC ([how to use](docs/docs/usage_instructions/using_hooks.md))
103
118
 
104
119
  [7.1.0]
120
+
105
121
  - `androidOldSku` is no longer required [#1438](https://github.com/dooboolab/react-native-iap/pull/1438).
106
122
 
107
123
  [6.1.0]
124
+
108
125
  - Creates two variants: `play` and `amazon` and only uses the required code.
109
126
  ```
110
127
  NOTE: This would be a breaking change with a very simple fix described in the documentation. To add: `missingDimensionStrategy 'store', 'play'` `in build.gradle`
111
128
  ```
112
- [3.0.0+]
113
- [react-native-iap V3 note][blog-v3-note]
129
+ [3.0.0+]
130
+ [react-native-iap V3 note][blog-v3-note]
131
+
132
+ ## Configuration of Google Play & iTunes Connect
114
133
 
115
- Configuration of Google Play & iTunes Connect
116
- ---------------------------------------------
117
134
  - Please refer to [Blog][blog-config-steps].
118
135
 
119
- [Deprecated README][readme-deprecated]
120
- --------------------------------------
136
+ ## [Deprecated README][readme-deprecated]
137
+
121
138
  - If you are using `react-native-iap@^2.*`, please follow the above README.
122
139
 
123
- Usage
124
- -----
140
+ ## Usage
141
+
125
142
  You can look in the [`RNIapExample/`][example] folder to try the example.
126
143
 
127
144
  NOTE: To run `RNIapExample` on Android use the variant flag as follows:
145
+
128
146
  ```
129
147
  yarn android --variant=MY_VARIANT
130
148
  ```
149
+
131
150
  where `MY_VARIANT` is `PlayDebug` or `AmazonDebug`
132
151
 
133
152
  Below is basic implementation which is also provided in `RNIapExample` project.
134
153
 
135
154
  If you want more advanced one please refer to [dooboolab.com/sponsor.tsx](https://github.com/hyochan/dooboolab.com/blob/master/src/components/pages/Sponsor.tsx)
136
155
 
137
- Sponsoring
138
- ----------
156
+ ## Sponsoring
139
157
 
140
158
  Since `IAP` itself is not perfect on each platform, we desperately need
141
159
  this project to be maintained. If you'd like to help us, please consider being
142
160
  with us in [Open Collective](https://opencollective.com/react-native-iap).
143
161
 
144
162
  ### Sponsors
163
+
145
164
  Support this project by becoming a sponsor. Your logo will show up here with
146
165
  a link to your website. [Become a sponsor][open-collective-sponsor].
147
166
  <a href="https://opencollective.com/react-native-iap#sponsors" target="_blank"><img src="https://opencollective.com/react-native-iap/sponsors.svg?width=890"></a>
148
167
 
149
168
  ### Backers
169
+
150
170
  Please be our [Backers][open-collective-backer].
151
171
  <a href="https://opencollective.com/react-native-iap#backers" target="_blank"><img src="https://opencollective.com/react-native-iap/backers.svg?width=890"></a>
152
172
 
153
173
  ### Contributing
174
+
154
175
  Please make sure to read the [Contributing Guide][contribute] before making a pull request.
155
176
  Thank you to all the people who helped to maintain and upgrade this project!
156
177
 
157
178
  <a href="graphs/contributors"><img src="https://opencollective.com/react-native-iap/contributors.svg?width=890" /></a>
179
+
158
180
  <hr>
159
181
 
160
182
  [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fdooboolab%2Freact-native-iap.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fdooboolab%2Freact-native-iap?ref=badge_large)
@@ -71,7 +71,7 @@ dependencies {
71
71
  implementation "com.android.support:support-annotations:$supportLibVersion"
72
72
  implementation "com.android.support:customtabs:$supportLibVersion"
73
73
  } else {
74
- def defaultAndroidXVersion = "1.+"
74
+ def defaultAndroidXVersion = "1.2.0"
75
75
  if (androidXVersion == null) {
76
76
  androidXVersion = defaultAndroidXVersion
77
77
  }
@@ -117,4 +117,14 @@ public class RNIapAmazonModule extends ReactContextBaseJavaModule {
117
117
  public void startListening(final Promise promise) {
118
118
  sendUnconsumedPurchases(promise);
119
119
  }
120
+
121
+ @ReactMethod
122
+ public void addListener(String eventName) {
123
+ // Keep: Required for RN built in Event Emitter Calls.
124
+ }
125
+
126
+ @ReactMethod
127
+ public void removeListeners(double count) {
128
+ // Keep: Required for RN built in Event Emitter Calls.
129
+ }
120
130
  }
@@ -36,7 +36,9 @@ import com.google.android.gms.common.ConnectionResult;
36
36
  import com.google.android.gms.common.GoogleApiAvailability;
37
37
  import java.math.BigDecimal;
38
38
  import java.util.ArrayList;
39
+ import java.util.HashMap;
39
40
  import java.util.List;
41
+ import java.util.Map;
40
42
 
41
43
  public class RNIapModule extends ReactContextBaseJavaModule implements PurchasesUpdatedListener {
42
44
  final String TAG = "RNIapModule";
@@ -45,12 +47,12 @@ public class RNIapModule extends ReactContextBaseJavaModule implements Purchases
45
47
  private final ReactContext reactContext;
46
48
  private BillingClient billingClientCache;
47
49
 
48
- private final List<SkuDetails> skus;
50
+ private final Map<String, SkuDetails> skus;
49
51
 
50
52
  public RNIapModule(ReactApplicationContext reactContext) {
51
53
  super(reactContext);
52
54
  this.reactContext = reactContext;
53
- this.skus = new ArrayList<>();
55
+ this.skus = new HashMap<>();
54
56
  LifecycleEventListener lifecycleEventListener =
55
57
  new LifecycleEventListener() {
56
58
  @Override
@@ -245,9 +247,7 @@ public class RNIapModule extends ReactContextBaseJavaModule implements Purchases
245
247
 
246
248
  if (skuDetailsList != null) {
247
249
  for (SkuDetails sku : skuDetailsList) {
248
- if (!skus.contains(sku)) {
249
- skus.add(sku);
250
- }
250
+ skus.put(sku.getSku(), sku);
251
251
  }
252
252
  }
253
253
  WritableNativeArray items = new WritableNativeArray();
@@ -417,13 +417,7 @@ public class RNIapModule extends ReactContextBaseJavaModule implements Purchases
417
417
  DoobooUtils.getInstance().addPromiseForKey(PROMISE_BUY_ITEM, promise);
418
418
  final BillingFlowParams.Builder builder = BillingFlowParams.newBuilder();
419
419
 
420
- SkuDetails selectedSku = null;
421
- for (SkuDetails skuDetail : skus) {
422
- if (skuDetail.getSku().equals(sku)) {
423
- selectedSku = skuDetail;
424
- break;
425
- }
426
- }
420
+ SkuDetails selectedSku = skus.get(sku);
427
421
 
428
422
  if (selectedSku == null) {
429
423
  String debugMessage =
@@ -583,9 +577,7 @@ public class RNIapModule extends ReactContextBaseJavaModule implements Purchases
583
577
  error.putString("message", errorData[1]);
584
578
  sendEvent(reactContext, "purchase-error", error);
585
579
 
586
- if (responseCode != BillingClient.BillingResponseCode.USER_CANCELED) {
587
- PlayUtils.getInstance().rejectPromisesWithBillingError(PROMISE_BUY_ITEM, responseCode);
588
- }
580
+ PlayUtils.getInstance().rejectPromisesWithBillingError(PROMISE_BUY_ITEM, responseCode);
589
581
  return;
590
582
  }
591
583
 
@@ -665,6 +657,16 @@ public class RNIapModule extends ReactContextBaseJavaModule implements Purchases
665
657
  sendUnconsumedPurchases(promise);
666
658
  }
667
659
 
660
+ @ReactMethod
661
+ public void addListener(String eventName) {
662
+ // Keep: Required for RN built in Event Emitter Calls.
663
+ }
664
+
665
+ @ReactMethod
666
+ public void removeListeners(double count) {
667
+ // Keep: Required for RN built in Event Emitter Calls.
668
+ }
669
+
668
670
  @ReactMethod
669
671
  public String getPackageName() {
670
672
  return getReactApplicationContext().getPackageName();
@@ -247,7 +247,7 @@
247
247
  GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
248
248
  GCC_WARN_UNUSED_FUNCTION = YES;
249
249
  GCC_WARN_UNUSED_VARIABLE = YES;
250
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
250
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
251
251
  MTL_ENABLE_DEBUG_INFO = YES;
252
252
  ONLY_ACTIVE_ARCH = YES;
253
253
  SDKROOT = iphoneos;
@@ -293,7 +293,7 @@
293
293
  GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
294
294
  GCC_WARN_UNUSED_FUNCTION = YES;
295
295
  GCC_WARN_UNUSED_VARIABLE = YES;
296
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
296
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
297
297
  MTL_ENABLE_DEBUG_INFO = NO;
298
298
  SDKROOT = iphoneos;
299
299
  VALIDATE_PRODUCT = YES;
package/ios/RNIapIos.m CHANGED
@@ -327,6 +327,7 @@ RCT_EXPORT_METHOD(getPendingTransactions:(RCTPromiseResolveBlock)resolve
327
327
  @(item.transactionDate.timeIntervalSince1970 * 1000), @"transactionDate",
328
328
  item.transactionIdentifier, @"transactionId",
329
329
  item.payment.productIdentifier, @"productId",
330
+ @(item.payment.quantity), @"quantityIOS",
330
331
  [receiptData base64EncodedStringWithOptions:0], @"transactionReceipt",
331
332
  nil
332
333
  ];
@@ -462,11 +463,9 @@ RCT_EXPORT_METHOD(presentCodeRedemptionSheet:(RCTPromiseResolveBlock)resolve
462
463
  [self sendEventWithName:@"purchase-error" body:err];
463
464
  }
464
465
 
465
- if (transaction.error.code != SKErrorPaymentCancelled) {
466
- [self rejectPromisesForKey:transaction.payment.productIdentifier code:[self standardErrorCode:(int)transaction.error.code]
467
- message:transaction.error.localizedDescription
468
- error:transaction.error];
469
- }
466
+ [self rejectPromisesForKey:transaction.payment.productIdentifier code:[self standardErrorCode:(int)transaction.error.code]
467
+ message:transaction.error.localizedDescription
468
+ error:transaction.error];
470
469
  });
471
470
  break;
472
471
  }
@@ -768,6 +767,7 @@ RCT_EXPORT_METHOD(presentCodeRedemptionSheet:(RCTPromiseResolveBlock)resolve
768
767
  @(transaction.transactionDate.timeIntervalSince1970 * 1000), @"transactionDate",
769
768
  transaction.transactionIdentifier, @"transactionId",
770
769
  transaction.payment.productIdentifier, @"productId",
770
+ @(transaction.payment.quantity), @"quantityIOS",
771
771
  [receiptData base64EncodedStringWithOptions:0], @"transactionReceipt",
772
772
  nil
773
773
  ];
@@ -0,0 +1,11 @@
1
+ // WIP Migrating from Objective C to swift
2
+ func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {
3
+ print("removedTransactions")
4
+ if countPendingTransaction != nil && countPendingTransaction > 0 {
5
+ countPendingTransaction -= transactions.count
6
+ if countPendingTransaction == 0 {
7
+ resolvePromises(forKey: "cleaningTransactions", value: nil)
8
+ countPendingTransaction = nil
9
+ }
10
+ }
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-iap",
3
- "version": "7.3.0",
3
+ "version": "7.5.1",
4
4
  "description": "React Native In App Purchase Module.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -43,31 +43,31 @@
43
43
  "dooboolab-welcome": "1.3.2"
44
44
  },
45
45
  "devDependencies": {
46
- "@babel/core": "7.14.8",
46
+ "@babel/core": "7.15.5",
47
47
  "@babel/plugin-proposal-class-properties": "7.14.5",
48
48
  "@babel/plugin-proposal-private-methods": "7.14.5",
49
- "@babel/preset-env": "7.14.8",
49
+ "@babel/preset-env": "7.15.6",
50
50
  "@babel/preset-react": "7.14.5",
51
- "@babel/preset-typescript": "7.14.5",
52
- "@dooboo/eslint-config": "0.8.2",
53
- "@testing-library/jest-native": "4.0.1",
51
+ "@babel/preset-typescript": "7.15.0",
52
+ "@dooboo/eslint-config": "0.8.5",
53
+ "@testing-library/jest-native": "4.0.2",
54
54
  "@testing-library/react-native": "7.2.0",
55
55
  "@types/eslint": "7.28.0",
56
- "@types/jest": "26.0.24",
57
- "@types/react": "17.0.15",
58
- "@types/react-native": "0.64.12",
56
+ "@types/jest": "27.0.1",
57
+ "@types/react": "17.0.21",
58
+ "@types/react-native": "0.65.0",
59
59
  "babel-core": "7.0.0-bridge.0",
60
60
  "babel-eslint": "10.1.0",
61
- "babel-jest": "27.0.6",
62
- "eslint": "7.31.0",
63
- "flow-bin": "0.156.0",
61
+ "babel-jest": "27.2.0",
62
+ "eslint": "7.32.0",
63
+ "flow-bin": "0.160.0",
64
64
  "flowgen": "1.14.1",
65
- "jest": "27.0.6",
65
+ "jest": "27.2.0",
66
66
  "metro-react-native-babel-preset": "0.66.2",
67
- "monolinter": "1.0.2",
68
- "prettier": "2.3.2",
67
+ "monolinter": "1.0.4",
68
+ "prettier": "2.4.1",
69
69
  "react-native": "0.64.2",
70
- "ts-jest": "27.0.4",
71
- "typescript": "4.3.5"
70
+ "ts-jest": "27.0.5",
71
+ "typescript": "4.4.3"
72
72
  }
73
73
  }
@@ -1,4 +1,5 @@
1
1
  import type { Product, Purchase, PurchaseError, Subscription } from '../types';
2
+ import { requestPurchase as iapRequestPurchase, requestSubscription as iapRequestSubscription } from '../iap';
2
3
  declare type IAP_STATUS = {
3
4
  connected: boolean;
4
5
  products: Product[];
@@ -8,11 +9,13 @@ declare type IAP_STATUS = {
8
9
  availablePurchases: Purchase[];
9
10
  currentPurchase?: Purchase;
10
11
  currentPurchaseError?: PurchaseError;
11
- finishTransaction: (purchase: Purchase) => Promise<string | void>;
12
+ finishTransaction: (purchase: Purchase, isConsumable?: boolean, developerPayloadAndroid?: string) => Promise<string | void>;
12
13
  getAvailablePurchases: () => Promise<void>;
13
14
  getPurchaseHistories: () => Promise<void>;
14
15
  getProducts: (skus: string[]) => Promise<void>;
15
16
  getSubscriptions: (skus: string[]) => Promise<void>;
17
+ requestPurchase: typeof iapRequestPurchase;
18
+ requestSubscription: typeof iapRequestSubscription;
16
19
  };
17
20
  export declare function useIAP(): IAP_STATUS;
18
21
  export {};
@@ -34,53 +34,38 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
34
34
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
35
  }
36
36
  };
37
- var __spreadArray = (this && this.__spreadArray) || function (to, from) {
38
- for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
39
- to[j] = from[i];
40
- return to;
41
- };
42
- import { NativeEventEmitter, NativeModules, } from 'react-native';
43
- import { endConnection, getPromotedProductIOS, getPurchaseHistory, finishTransaction as iapFinishTransaction, getAvailablePurchases as iapGetAvailablePurchases, getProducts as iapGetProducts, getSubscriptions as iapGetSubscriptions, initConnection, purchaseErrorListener, purchaseUpdatedListener, } from '../iap';
44
- import { useCallback, useEffect, useState } from 'react';
45
- var RNIapIos = NativeModules.RNIapIos;
46
- var IAPEmitter = new NativeEventEmitter(RNIapIos);
47
- var purchaseUpdateSubscription;
48
- var purchaseErrorSubscription;
49
- var promotedProductsSubscription;
37
+ import { getPurchaseHistory, finishTransaction as iapFinishTransaction, getAvailablePurchases as iapGetAvailablePurchases, getProducts as iapGetProducts, getSubscriptions as iapGetSubscriptions, requestPurchase as iapRequestPurchase, requestSubscription as iapRequestSubscription, } from '../iap';
38
+ import { useCallback } from 'react';
39
+ import { useIAPContext } from './withIAPContext';
50
40
  export function useIAP() {
51
41
  var _this = this;
52
- var _a = useState(false), connected = _a[0], setConnected = _a[1];
53
- var _b = useState([]), products = _b[0], setProducts = _b[1];
54
- var _c = useState([]), promotedProductsIOS = _c[0], setPromotedProductsIOS = _c[1];
55
- var _d = useState([]), subscriptions = _d[0], setSubscriptions = _d[1];
56
- var _e = useState([]), purchaseHistories = _e[0], setPurchaseHistories = _e[1];
57
- var _f = useState([]), availablePurchases = _f[0], setAvailablePurchases = _f[1];
58
- var _g = useState(), currentPurchase = _g[0], setCurrentPurchase = _g[1];
59
- var _h = useState(), currentPurchaseError = _h[0], setCurrentPurchaseError = _h[1];
42
+ var _a = useIAPContext(), connected = _a.connected, products = _a.products, promotedProductsIOS = _a.promotedProductsIOS, subscriptions = _a.subscriptions, purchaseHistories = _a.purchaseHistories, availablePurchases = _a.availablePurchases, currentPurchase = _a.currentPurchase, currentPurchaseError = _a.currentPurchaseError, setProducts = _a.setProducts, setSubscriptions = _a.setSubscriptions, setAvailablePurchases = _a.setAvailablePurchases, setPurchaseHistories = _a.setPurchaseHistories, setCurrentPurchase = _a.setCurrentPurchase, setCurrentPurchaseError = _a.setCurrentPurchaseError;
60
43
  var getProducts = useCallback(function (skus) { return __awaiter(_this, void 0, void 0, function () {
61
- var iaps;
62
- return __generator(this, function (_a) {
63
- switch (_a.label) {
64
- case 0: return [4 /*yield*/, iapGetProducts(skus)];
44
+ var _a;
45
+ return __generator(this, function (_b) {
46
+ switch (_b.label) {
47
+ case 0:
48
+ _a = setProducts;
49
+ return [4 /*yield*/, iapGetProducts(skus)];
65
50
  case 1:
66
- iaps = _a.sent();
67
- setProducts(iaps);
51
+ _a.apply(void 0, [_b.sent()]);
68
52
  return [2 /*return*/];
69
53
  }
70
54
  });
71
- }); }, []);
55
+ }); }, [setProducts]);
72
56
  var getSubscriptions = useCallback(function (skus) { return __awaiter(_this, void 0, void 0, function () {
73
- var subs;
74
- return __generator(this, function (_a) {
75
- switch (_a.label) {
76
- case 0: return [4 /*yield*/, iapGetSubscriptions(skus)];
57
+ var _a;
58
+ return __generator(this, function (_b) {
59
+ switch (_b.label) {
60
+ case 0:
61
+ _a = setSubscriptions;
62
+ return [4 /*yield*/, iapGetSubscriptions(skus)];
77
63
  case 1:
78
- subs = _a.sent();
79
- setSubscriptions(subs);
64
+ _a.apply(void 0, [_b.sent()]);
80
65
  return [2 /*return*/];
81
66
  }
82
67
  });
83
- }); }, []);
68
+ }); }, [setSubscriptions]);
84
69
  var getAvailablePurchases = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
85
70
  var _a;
86
71
  return __generator(this, function (_b) {
@@ -93,7 +78,7 @@ export function useIAP() {
93
78
  return [2 /*return*/];
94
79
  }
95
80
  });
96
- }); }, []);
81
+ }); }, [setAvailablePurchases]);
97
82
  var getPurchaseHistories = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
98
83
  var _a;
99
84
  return __generator(this, function (_b) {
@@ -106,7 +91,7 @@ export function useIAP() {
106
91
  return [2 /*return*/];
107
92
  }
108
93
  });
109
- }); }, []);
94
+ }); }, [setPurchaseHistories]);
110
95
  var finishTransaction = useCallback(function (purchase, isConsumable, developerPayloadAndroid) { return __awaiter(_this, void 0, void 0, function () {
111
96
  var err_1;
112
97
  return __generator(this, function (_a) {
@@ -117,7 +102,7 @@ export function useIAP() {
117
102
  case 1: return [2 /*return*/, _a.sent()];
118
103
  case 2:
119
104
  err_1 = _a.sent();
120
- throw new Error(err_1);
105
+ throw err_1;
121
106
  case 3:
122
107
  if (purchase.productId === (currentPurchase === null || currentPurchase === void 0 ? void 0 : currentPurchase.productId))
123
108
  setCurrentPurchase(undefined);
@@ -127,58 +112,12 @@ export function useIAP() {
127
112
  case 4: return [2 /*return*/];
128
113
  }
129
114
  });
130
- }); }, [currentPurchase === null || currentPurchase === void 0 ? void 0 : currentPurchase.productId, currentPurchaseError === null || currentPurchaseError === void 0 ? void 0 : currentPurchaseError.productId]);
131
- var initIapWithSubscriptions = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
132
- var result;
133
- var _this = this;
134
- return __generator(this, function (_a) {
135
- switch (_a.label) {
136
- case 0: return [4 /*yield*/, initConnection()];
137
- case 1:
138
- result = _a.sent();
139
- setConnected(result);
140
- if (result) {
141
- purchaseUpdateSubscription = purchaseUpdatedListener(function (purchase) { return __awaiter(_this, void 0, void 0, function () {
142
- return __generator(this, function (_a) {
143
- setCurrentPurchaseError(undefined);
144
- setCurrentPurchase(purchase);
145
- return [2 /*return*/];
146
- });
147
- }); });
148
- purchaseErrorSubscription = purchaseErrorListener(function (error) {
149
- setCurrentPurchase(undefined);
150
- setCurrentPurchaseError(error);
151
- });
152
- promotedProductsSubscription = IAPEmitter.addListener('iap-promoted-product', function () { return __awaiter(_this, void 0, void 0, function () {
153
- var product;
154
- return __generator(this, function (_a) {
155
- switch (_a.label) {
156
- case 0: return [4 /*yield*/, getPromotedProductIOS()];
157
- case 1:
158
- product = _a.sent();
159
- setPromotedProductsIOS(function (prevProducts) { return __spreadArray(__spreadArray([], prevProducts), (product ? [product] : [])); });
160
- return [2 /*return*/];
161
- }
162
- });
163
- }); });
164
- }
165
- return [2 /*return*/];
166
- }
167
- });
168
- }); }, []);
169
- useEffect(function () {
170
- initIapWithSubscriptions();
171
- return function () {
172
- if (purchaseUpdateSubscription)
173
- purchaseUpdateSubscription.remove();
174
- if (purchaseErrorSubscription)
175
- purchaseErrorSubscription.remove();
176
- if (promotedProductsSubscription)
177
- promotedProductsSubscription.remove();
178
- endConnection();
179
- setConnected(false);
180
- };
181
- }, [initIapWithSubscriptions]);
115
+ }); }, [
116
+ currentPurchase === null || currentPurchase === void 0 ? void 0 : currentPurchase.productId,
117
+ currentPurchaseError === null || currentPurchaseError === void 0 ? void 0 : currentPurchaseError.productId,
118
+ setCurrentPurchase,
119
+ setCurrentPurchaseError,
120
+ ]);
182
121
  return {
183
122
  connected: connected,
184
123
  products: products,
@@ -193,5 +132,7 @@ export function useIAP() {
193
132
  getSubscriptions: getSubscriptions,
194
133
  getAvailablePurchases: getAvailablePurchases,
195
134
  getPurchaseHistories: getPurchaseHistories,
135
+ requestPurchase: iapRequestPurchase,
136
+ requestSubscription: iapRequestSubscription,
196
137
  };
197
138
  }
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { Product, Purchase, PurchaseError, Subscription } from '../types';
3
+ declare type IAPContextType = {
4
+ connected: boolean;
5
+ products: Product[];
6
+ promotedProductsIOS: Product[];
7
+ subscriptions: Subscription[];
8
+ purchaseHistories: Purchase[];
9
+ availablePurchases: Purchase[];
10
+ currentPurchase?: Purchase;
11
+ currentPurchaseError?: PurchaseError;
12
+ setProducts: (products: Product[]) => void;
13
+ setSubscriptions: (subscriptions: Subscription[]) => void;
14
+ setPurchaseHistories: (purchaseHistories: Purchase[]) => void;
15
+ setAvailablePurchases: (availablePurchases: Purchase[]) => void;
16
+ setCurrentPurchase: (currentPurchase: Purchase | undefined) => void;
17
+ setCurrentPurchaseError: (currentPurchaseError: PurchaseError | undefined) => void;
18
+ };
19
+ export declare function useIAPContext(): IAPContextType;
20
+ export declare function withIAPContext<T>(Component: React.ComponentType<T>): (props: T) => JSX.Element;
21
+ export {};
@@ -0,0 +1,140 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (_) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
38
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
39
+ if (ar || !(i in from)) {
40
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
41
+ ar[i] = from[i];
42
+ }
43
+ }
44
+ return to.concat(ar || Array.prototype.slice.call(from));
45
+ };
46
+ import React, { useContext, useEffect, useMemo, useState } from 'react';
47
+ import { NativeEventEmitter, NativeModules } from 'react-native';
48
+ import { getPromotedProductIOS, initConnection, purchaseErrorListener, purchaseUpdatedListener, } from '../iap';
49
+ var RNIapIos = NativeModules.RNIapIos;
50
+ var IAPEmitter = new NativeEventEmitter(RNIapIos);
51
+ // @ts-ignore
52
+ var IAPContext = React.createContext(null);
53
+ export function useIAPContext() {
54
+ var ctx = useContext(IAPContext);
55
+ if (!ctx)
56
+ throw new Error('You need wrap your app with withIAPContext HOC');
57
+ return ctx;
58
+ }
59
+ export function withIAPContext(Component) {
60
+ return function WrapperComponent(props) {
61
+ var _this = this;
62
+ var _a = useState(false), connected = _a[0], setConnected = _a[1];
63
+ var _b = useState([]), products = _b[0], setProducts = _b[1];
64
+ var _c = useState([]), promotedProductsIOS = _c[0], setPromotedProductsIOS = _c[1];
65
+ var _d = useState([]), subscriptions = _d[0], setSubscriptions = _d[1];
66
+ var _e = useState([]), purchaseHistories = _e[0], setPurchaseHistories = _e[1];
67
+ var _f = useState([]), availablePurchases = _f[0], setAvailablePurchases = _f[1];
68
+ var _g = useState(), currentPurchase = _g[0], setCurrentPurchase = _g[1];
69
+ var _h = useState(), currentPurchaseError = _h[0], setCurrentPurchaseError = _h[1];
70
+ var context = useMemo(function () { return ({
71
+ connected: connected,
72
+ products: products,
73
+ subscriptions: subscriptions,
74
+ promotedProductsIOS: promotedProductsIOS,
75
+ purchaseHistories: purchaseHistories,
76
+ availablePurchases: availablePurchases,
77
+ currentPurchase: currentPurchase,
78
+ currentPurchaseError: currentPurchaseError,
79
+ setProducts: setProducts,
80
+ setSubscriptions: setSubscriptions,
81
+ setPurchaseHistories: setPurchaseHistories,
82
+ setAvailablePurchases: setAvailablePurchases,
83
+ setCurrentPurchase: setCurrentPurchase,
84
+ setCurrentPurchaseError: setCurrentPurchaseError,
85
+ }); }, [
86
+ connected,
87
+ products,
88
+ subscriptions,
89
+ promotedProductsIOS,
90
+ purchaseHistories,
91
+ availablePurchases,
92
+ currentPurchase,
93
+ currentPurchaseError,
94
+ setProducts,
95
+ setSubscriptions,
96
+ setPurchaseHistories,
97
+ setAvailablePurchases,
98
+ setCurrentPurchase,
99
+ setCurrentPurchaseError,
100
+ ]);
101
+ useEffect(function () {
102
+ initConnection().then(setConnected);
103
+ }, []);
104
+ useEffect(function () {
105
+ if (!connected)
106
+ return;
107
+ var purchaseUpdateSubscription = purchaseUpdatedListener(function (purchase) { return __awaiter(_this, void 0, void 0, function () {
108
+ return __generator(this, function (_a) {
109
+ setCurrentPurchaseError(undefined);
110
+ setCurrentPurchase(purchase);
111
+ return [2 /*return*/];
112
+ });
113
+ }); });
114
+ var purchaseErrorSubscription = purchaseErrorListener(function (error) {
115
+ setCurrentPurchase(undefined);
116
+ setCurrentPurchaseError(error);
117
+ });
118
+ var promotedProductsSubscription = IAPEmitter.addListener('iap-promoted-product', function () { return __awaiter(_this, void 0, void 0, function () {
119
+ var product;
120
+ return __generator(this, function (_a) {
121
+ switch (_a.label) {
122
+ case 0: return [4 /*yield*/, getPromotedProductIOS()];
123
+ case 1:
124
+ product = _a.sent();
125
+ setPromotedProductsIOS(function (prevProducts) { return __spreadArray(__spreadArray([], prevProducts, true), (product ? [product] : []), true); });
126
+ return [2 /*return*/];
127
+ }
128
+ });
129
+ }); });
130
+ return function () {
131
+ purchaseUpdateSubscription.remove();
132
+ purchaseErrorSubscription.remove();
133
+ promotedProductsSubscription.remove();
134
+ };
135
+ }, [connected]);
136
+ return (<IAPContext.Provider value={context}>
137
+ <Component {...props}/>
138
+ </IAPContext.Provider>);
139
+ };
140
+ }
package/src/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './types';
2
2
  export * from './hooks/useIAP';
3
+ export * from './hooks/withIAPContext';
3
4
  export * from './iap';
package/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './types';
2
2
  export * from './hooks/useIAP';
3
+ export * from './hooks/withIAPContext';
3
4
  export * from './iap';
@@ -40,7 +40,7 @@ export interface ProductCommon {
40
40
  price: string;
41
41
  currency: string;
42
42
  localizedPrice: string;
43
- countryCodeIOS?: string;
43
+ countryCode?: string;
44
44
  }
45
45
  export interface ProductPurchase {
46
46
  productId: string;
@@ -48,6 +48,7 @@ export interface ProductPurchase {
48
48
  transactionDate: number;
49
49
  transactionReceipt: string;
50
50
  purchaseToken?: string;
51
+ quantityIOS?: number;
51
52
  originalTransactionDateIOS?: string;
52
53
  originalTransactionIdentifierIOS?: string;
53
54
  dataAndroid?: string;