react-native-iap 9.0.0-beta9 → 9.0.0-rc.3
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 +14 -1
- package/android/src/amazon/java/com/dooboolab/RNIap/RNIapAmazonModule.kt +0 -5
- package/android/src/play/java/com/dooboolab/RNIap/RNIapModule.kt +70 -66
- package/android/src/testPlay/java/com/dooboolab/RNIap/RNIapModuleTest.kt +0 -2
- package/ios/RNIapIos.swift +30 -17
- package/lib/commonjs/hooks/withIAPContext.js +1 -1
- package/lib/commonjs/hooks/withIAPContext.js.map +1 -1
- package/lib/commonjs/iap.js +54 -9
- package/lib/commonjs/iap.js.map +1 -1
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/module/hooks/withIAPContext.js +1 -1
- package/lib/module/hooks/withIAPContext.js.map +1 -1
- package/lib/module/iap.js +46 -7
- package/lib/module/iap.js.map +1 -1
- package/lib/module/types/index.js.map +1 -1
- package/lib/typescript/iap.d.ts +17 -4
- package/lib/typescript/types/index.d.ts +40 -42
- package/package.json +1 -1
- package/src/hooks/withIAPContext.tsx +1 -1
- package/src/iap.ts +56 -19
- package/src/types/index.ts +55 -56
package/README.md
CHANGED
|
@@ -19,9 +19,22 @@
|
|
|
19
19
|
|
|
20
20
|
Published in [website](https://react-native-iap.dooboolab.com).
|
|
21
21
|
|
|
22
|
+
## Our maintainers
|
|
23
|
+
|
|
24
|
+
Please [fund the project](https://opencollective.com/react-native-iap) if you are willing the maintainers to make the repository sustainable.
|
|
25
|
+
|
|
26
|
+
- [andresesfm](https://github.com/andresesfm)
|
|
27
|
+
- [jeremybarbet](https://github.com/jeremybarbet)
|
|
28
|
+
|
|
29
|
+
> The fund goes to maintainers.
|
|
30
|
+
|
|
31
|
+
### Supporter
|
|
32
|
+
|
|
33
|
+
- [hyochan](https://github.com/hyochan)
|
|
34
|
+
|
|
22
35
|
## Announcement
|
|
23
36
|
|
|
24
|
-
- Version `9.0.0` is currently in release candidate. The module migrates android sdk to [play billing library v5](https://qonversion.io/blog/google-play-billing-library-5-0) and iOS sdk to [storekit2](https://developer.apple.com/videos/play/wwdc2021/10114). Our core
|
|
37
|
+
- Version `9.0.0` is currently in release candidate. The module migrates android sdk to [play billing library v5](https://qonversion.io/blog/google-play-billing-library-5-0) and iOS sdk to [storekit2](https://developer.apple.com/videos/play/wwdc2021/10114). Our core maintainers [andresesfm](https://github.com/andresesfm) and [jeremybarbet](https://github.com/jeremybarbet) are working hard on this.
|
|
25
38
|
|
|
26
39
|
```
|
|
27
40
|
yarn add react-native-iap@next
|
|
@@ -69,12 +69,7 @@ class RNIapAmazonModule(reactContext: ReactApplicationContext) :
|
|
|
69
69
|
|
|
70
70
|
@ReactMethod
|
|
71
71
|
fun buyItemByType(
|
|
72
|
-
type: String?,
|
|
73
72
|
sku: String?,
|
|
74
|
-
purchaseToken: String?,
|
|
75
|
-
prorationMode: Int?,
|
|
76
|
-
obfuscatedAccountId: String?,
|
|
77
|
-
obfuscatedProfileId: String?,
|
|
78
73
|
promise: Promise
|
|
79
74
|
) {
|
|
80
75
|
DoobooUtils.instance.addPromiseForKey(PROMISE_BUY_ITEM, promise)
|
|
@@ -87,7 +87,7 @@ class RNIapModule(
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
@ReactMethod
|
|
90
|
-
|
|
90
|
+
fun initConnection(promise: Promise) {
|
|
91
91
|
if (googleApiAvailability.isGooglePlayServicesAvailable(reactContext)
|
|
92
92
|
!= ConnectionResult.SUCCESS
|
|
93
93
|
) {
|
|
@@ -108,13 +108,13 @@ class RNIapModule(
|
|
|
108
108
|
billingClientCache = it
|
|
109
109
|
it.startConnection(
|
|
110
110
|
object : BillingClientStateListener {
|
|
111
|
-
|
|
111
|
+
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
|
112
112
|
if (!isValidResult(billingResult, promise)) return
|
|
113
113
|
|
|
114
114
|
promise.safeResolve(true)
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
override fun onBillingServiceDisconnected() {
|
|
118
118
|
Log.i(TAG, "Billing service disconnected")
|
|
119
119
|
}
|
|
120
120
|
}
|
|
@@ -123,7 +123,7 @@ class RNIapModule(
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
@ReactMethod
|
|
126
|
-
|
|
126
|
+
fun endConnection(promise: Promise) {
|
|
127
127
|
billingClientCache?.endConnection()
|
|
128
128
|
billingClientCache = null
|
|
129
129
|
promise.safeResolve(true)
|
|
@@ -160,7 +160,7 @@ class RNIapModule(
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
@ReactMethod
|
|
163
|
-
|
|
163
|
+
fun flushFailedPurchasesCachedAsPending(promise: Promise) {
|
|
164
164
|
ensureConnection(
|
|
165
165
|
promise
|
|
166
166
|
) { billingClient ->
|
|
@@ -193,7 +193,7 @@ class RNIapModule(
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
@ReactMethod
|
|
196
|
-
|
|
196
|
+
fun getItemsByType(type: String, skuArr: ReadableArray, promise: Promise) {
|
|
197
197
|
ensureConnection(
|
|
198
198
|
promise
|
|
199
199
|
) { billingClient ->
|
|
@@ -317,37 +317,34 @@ class RNIapModule(
|
|
|
317
317
|
).build()
|
|
318
318
|
) { billingResult: BillingResult, purchases: List<Purchase>? ->
|
|
319
319
|
if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
)
|
|
346
|
-
if (type == BillingClient.ProductType.SUBS) {
|
|
347
|
-
item.putBoolean("autoRenewingAndroid", purchase.isAutoRenewing)
|
|
348
|
-
}
|
|
349
|
-
items.pushMap(item)
|
|
320
|
+
purchases?.forEach { purchase ->
|
|
321
|
+
val item = WritableNativeMap()
|
|
322
|
+
item.putString("productId", purchase.products[0]) // kept for convenience/backward-compatibility. productIds has the complete list
|
|
323
|
+
val products = Arguments.createArray()
|
|
324
|
+
purchase.products.forEach { products.pushString(it) }
|
|
325
|
+
item.putArray("productIds", products)
|
|
326
|
+
item.putString("transactionId", purchase.orderId)
|
|
327
|
+
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
328
|
+
item.putString("transactionReceipt", purchase.originalJson)
|
|
329
|
+
item.putString("orderId", purchase.orderId)
|
|
330
|
+
item.putString("purchaseToken", purchase.purchaseToken)
|
|
331
|
+
item.putString("developerPayloadAndroid", purchase.developerPayload)
|
|
332
|
+
item.putString("signatureAndroid", purchase.signature)
|
|
333
|
+
item.putInt("purchaseStateAndroid", purchase.purchaseState)
|
|
334
|
+
item.putBoolean("isAcknowledgedAndroid", purchase.isAcknowledged)
|
|
335
|
+
item.putString("packageNameAndroid", purchase.packageName)
|
|
336
|
+
item.putString(
|
|
337
|
+
"obfuscatedAccountIdAndroid",
|
|
338
|
+
purchase.accountIdentifiers?.obfuscatedAccountId
|
|
339
|
+
)
|
|
340
|
+
item.putString(
|
|
341
|
+
"obfuscatedProfileIdAndroid",
|
|
342
|
+
purchase.accountIdentifiers?.obfuscatedProfileId
|
|
343
|
+
)
|
|
344
|
+
if (type == BillingClient.ProductType.SUBS) {
|
|
345
|
+
item.putBoolean("autoRenewingAndroid", purchase.isAutoRenewing)
|
|
350
346
|
}
|
|
347
|
+
items.pushMap(item)
|
|
351
348
|
}
|
|
352
349
|
promise.safeResolve(items)
|
|
353
350
|
}
|
|
@@ -397,7 +394,8 @@ class RNIapModule(
|
|
|
397
394
|
prorationMode: Int,
|
|
398
395
|
obfuscatedAccountId: String?,
|
|
399
396
|
obfuscatedProfileId: String?,
|
|
400
|
-
|
|
397
|
+
offerTokenArr: ReadableArray, // New parameter in V5
|
|
398
|
+
isOfferPersonalized: Boolean, // New parameter in V5
|
|
401
399
|
promise: Promise
|
|
402
400
|
) {
|
|
403
401
|
val activity = currentActivity
|
|
@@ -412,36 +410,42 @@ class RNIapModule(
|
|
|
412
410
|
PROMISE_BUY_ITEM,
|
|
413
411
|
promise
|
|
414
412
|
)
|
|
413
|
+
if (type == BillingClient.ProductType.SUBS && skuArr.size() != offerTokenArr.size()) {
|
|
414
|
+
val debugMessage =
|
|
415
|
+
"The number of skus (${skuArr.size()}) must match: the number of offerTokens (${offerTokenArr.size()}) for Subscriptions"
|
|
416
|
+
val error = Arguments.createMap()
|
|
417
|
+
error.putString("debugMessage", debugMessage)
|
|
418
|
+
error.putString("code", PROMISE_BUY_ITEM)
|
|
419
|
+
error.putString("message", debugMessage)
|
|
420
|
+
sendEvent(reactContext, "purchase-error", error)
|
|
421
|
+
promise.safeReject(PROMISE_BUY_ITEM, debugMessage)
|
|
422
|
+
return@ensureConnection
|
|
423
|
+
}
|
|
415
424
|
val productParamsList =
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
)
|
|
436
|
-
) {
|
|
437
|
-
val offerToken =
|
|
438
|
-
selectedSku.subscriptionOfferDetails?.get(selectedOfferIndex)?.offerToken
|
|
439
|
-
offerToken?.let { productParams = productParams.setOfferToken(offerToken) }
|
|
425
|
+
skuArr.toArrayList().map { it.toString() }.mapIndexed { index, sku ->
|
|
426
|
+
val selectedSku: ProductDetails? = skus[sku]
|
|
427
|
+
if (selectedSku == null) {
|
|
428
|
+
val debugMessage =
|
|
429
|
+
"The sku was not found. Please fetch products first by calling getItems"
|
|
430
|
+
val error = Arguments.createMap()
|
|
431
|
+
error.putString("debugMessage", debugMessage)
|
|
432
|
+
error.putString("code", PROMISE_BUY_ITEM)
|
|
433
|
+
error.putString("message", debugMessage)
|
|
434
|
+
error.putString("productId", sku)
|
|
435
|
+
sendEvent(reactContext, "purchase-error", error)
|
|
436
|
+
promise.safeReject(PROMISE_BUY_ITEM, debugMessage)
|
|
437
|
+
return@ensureConnection
|
|
438
|
+
}
|
|
439
|
+
var productDetailParams = BillingFlowParams.ProductDetailsParams.newBuilder().setProductDetails(selectedSku)
|
|
440
|
+
if (type == BillingClient.ProductType.SUBS) {
|
|
441
|
+
val offerToken = offerTokenArr.getString(index)
|
|
442
|
+
productDetailParams = productDetailParams.setOfferToken(offerToken)
|
|
443
|
+
}
|
|
444
|
+
productDetailParams.build()
|
|
440
445
|
}
|
|
441
|
-
productParams.build()
|
|
442
|
-
}
|
|
443
446
|
val builder = BillingFlowParams.newBuilder()
|
|
444
|
-
builder.setProductDetailsParamsList(productParamsList)
|
|
447
|
+
builder.setProductDetailsParamsList(productParamsList).setIsOfferPersonalized(isOfferPersonalized)
|
|
448
|
+
|
|
445
449
|
val subscriptionUpdateParamsBuilder = SubscriptionUpdateParams.newBuilder()
|
|
446
450
|
if (purchaseToken != null) {
|
|
447
451
|
subscriptionUpdateParamsBuilder.setOldPurchaseToken(purchaseToken)
|
|
@@ -571,7 +575,7 @@ class RNIapModule(
|
|
|
571
575
|
.getBillingResponseData(billingResult.responseCode)
|
|
572
576
|
map.putString("code", errorData[0])
|
|
573
577
|
map.putString("message", errorData[1])
|
|
574
|
-
map.putString("purchaseToken",purchaseToken)
|
|
578
|
+
map.putString("purchaseToken", purchaseToken)
|
|
575
579
|
promise.safeResolve(map)
|
|
576
580
|
}
|
|
577
581
|
}
|
|
@@ -621,7 +625,7 @@ class RNIapModule(
|
|
|
621
625
|
accountIdentifiers.obfuscatedProfileId
|
|
622
626
|
)
|
|
623
627
|
}
|
|
624
|
-
promiseItems.pushMap(item)
|
|
628
|
+
promiseItems.pushMap(item.copy())
|
|
625
629
|
sendEvent(reactContext, "purchase-updated", item)
|
|
626
630
|
}
|
|
627
631
|
DoobooUtils.instance.resolvePromisesForKey(PROMISE_BUY_ITEM, promiseItems)
|
|
@@ -4,12 +4,10 @@ import com.android.billingclient.api.BillingClient
|
|
|
4
4
|
import com.android.billingclient.api.BillingClientStateListener
|
|
5
5
|
import com.android.billingclient.api.BillingResult
|
|
6
6
|
import com.android.billingclient.api.ConsumeResponseListener
|
|
7
|
-
import com.android.billingclient.api.ProductDetails
|
|
8
7
|
import com.android.billingclient.api.ProductDetailsResponseListener
|
|
9
8
|
import com.android.billingclient.api.Purchase
|
|
10
9
|
import com.android.billingclient.api.PurchasesResponseListener
|
|
11
10
|
import com.android.billingclient.api.QueryPurchasesParams
|
|
12
|
-
import com.android.billingclient.api.SkuDetailsResponseListener
|
|
13
11
|
import com.facebook.react.bridge.Arguments
|
|
14
12
|
import com.facebook.react.bridge.Promise
|
|
15
13
|
import com.facebook.react.bridge.ReactApplicationContext
|
package/ios/RNIapIos.swift
CHANGED
|
@@ -43,7 +43,8 @@ class RNIapIos: RCTEventEmitter, SKRequestDelegate, SKPaymentTransactionObserver
|
|
|
43
43
|
private var promotedPayment: SKPayment?
|
|
44
44
|
private var promotedProduct: SKProduct?
|
|
45
45
|
private var productsRequest: SKProductsRequest?
|
|
46
|
-
private var countPendingTransaction: Int
|
|
46
|
+
private var countPendingTransaction: Int = 0
|
|
47
|
+
private var hasTransactionObserver = false
|
|
47
48
|
|
|
48
49
|
override init() {
|
|
49
50
|
promisesByKey = [String: [RNIapIosPromise]]()
|
|
@@ -51,17 +52,31 @@ class RNIapIos: RCTEventEmitter, SKRequestDelegate, SKPaymentTransactionObserver
|
|
|
51
52
|
myQueue = DispatchQueue(label: "reject")
|
|
52
53
|
validProducts = [SKProduct]()
|
|
53
54
|
super.init()
|
|
54
|
-
|
|
55
|
+
addTransactionObserver()
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
deinit {
|
|
58
|
-
|
|
59
|
+
removeTransactionObserver()
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
override class func requiresMainQueueSetup() -> Bool {
|
|
62
63
|
return true
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
func addTransactionObserver() {
|
|
67
|
+
if !hasTransactionObserver {
|
|
68
|
+
hasTransactionObserver = true
|
|
69
|
+
SKPaymentQueue.default().add(self)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func removeTransactionObserver() {
|
|
74
|
+
if hasTransactionObserver {
|
|
75
|
+
hasTransactionObserver = false
|
|
76
|
+
SKPaymentQueue.default().remove(self)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
65
80
|
func flushUnheardEvents() {
|
|
66
81
|
paymentQueue(SKPaymentQueue.default(), updatedTransactions: SKPaymentQueue.default().transactions)
|
|
67
82
|
}
|
|
@@ -136,6 +151,7 @@ class RNIapIos: RCTEventEmitter, SKRequestDelegate, SKPaymentTransactionObserver
|
|
|
136
151
|
_ resolve: @escaping RCTPromiseResolveBlock = { _ in },
|
|
137
152
|
reject: @escaping RCTPromiseRejectBlock = { _, _, _ in }
|
|
138
153
|
) {
|
|
154
|
+
addTransactionObserver()
|
|
139
155
|
let canMakePayments = SKPaymentQueue.canMakePayments()
|
|
140
156
|
resolve(NSNumber(value: canMakePayments))
|
|
141
157
|
}
|
|
@@ -143,7 +159,7 @@ class RNIapIos: RCTEventEmitter, SKRequestDelegate, SKPaymentTransactionObserver
|
|
|
143
159
|
_ resolve: @escaping RCTPromiseResolveBlock = { _ in },
|
|
144
160
|
reject: @escaping RCTPromiseRejectBlock = { _, _, _ in }
|
|
145
161
|
) {
|
|
146
|
-
|
|
162
|
+
removeTransactionObserver()
|
|
147
163
|
resolve(nil)
|
|
148
164
|
}
|
|
149
165
|
@objc public func getItems(
|
|
@@ -300,18 +316,19 @@ class RNIapIos: RCTEventEmitter, SKRequestDelegate, SKPaymentTransactionObserver
|
|
|
300
316
|
_ resolve: @escaping RCTPromiseResolveBlock = { _ in },
|
|
301
317
|
reject: @escaping RCTPromiseRejectBlock = { _, _, _ in }
|
|
302
318
|
) {
|
|
303
|
-
debugMessage("clear remaining Transactions. Call this before make a new transaction")
|
|
304
|
-
|
|
305
319
|
let pendingTrans = SKPaymentQueue.default().transactions
|
|
306
|
-
|
|
320
|
+
countPendingTransaction = pendingTrans.count
|
|
321
|
+
|
|
322
|
+
debugMessage("clear remaining Transactions (\(countPendingTransaction)). Call this before make a new transaction")
|
|
307
323
|
|
|
308
324
|
if countPendingTransaction > 0 {
|
|
309
325
|
addPromise(forKey: "cleaningTransactions", resolve: resolve, reject: reject)
|
|
310
326
|
for transaction in pendingTrans {
|
|
311
327
|
SKPaymentQueue.default().finishTransaction(transaction)
|
|
312
328
|
}
|
|
329
|
+
} else {
|
|
330
|
+
resolve(nil)
|
|
313
331
|
}
|
|
314
|
-
resolve(nil)
|
|
315
332
|
}
|
|
316
333
|
|
|
317
334
|
@objc public func clearProducts(
|
|
@@ -936,18 +953,14 @@ class RNIapIos: RCTEventEmitter, SKRequestDelegate, SKPaymentTransactionObserver
|
|
|
936
953
|
}
|
|
937
954
|
|
|
938
955
|
func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {
|
|
939
|
-
debugMessage("removedTransactions")
|
|
956
|
+
debugMessage("removedTransactions - countPendingTransactions \(countPendingTransaction)")
|
|
940
957
|
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
if unwrappedCount > 0 {
|
|
946
|
-
unwrappedCount -= transactions.count
|
|
958
|
+
if countPendingTransaction > 0 {
|
|
959
|
+
countPendingTransaction -= transactions.count
|
|
947
960
|
|
|
948
|
-
if
|
|
961
|
+
if countPendingTransaction <= 0 {
|
|
949
962
|
resolvePromises(forKey: "cleaningTransactions", value: nil)
|
|
950
|
-
countPendingTransaction =
|
|
963
|
+
countPendingTransaction = 0
|
|
951
964
|
}
|
|
952
965
|
}
|
|
953
966
|
}
|
|
@@ -81,7 +81,7 @@ function withIAPContext(Component) {
|
|
|
81
81
|
return () => {
|
|
82
82
|
purchaseUpdateSubscription.remove();
|
|
83
83
|
purchaseErrorSubscription.remove();
|
|
84
|
-
promotedProductSubscription.remove();
|
|
84
|
+
promotedProductSubscription === null || promotedProductSubscription === void 0 ? void 0 : promotedProductSubscription.remove();
|
|
85
85
|
};
|
|
86
86
|
}, [connected]);
|
|
87
87
|
return /*#__PURE__*/_react.default.createElement(IAPContext.Provider, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["IAPContext","React","createContext","useIAPContext","ctx","useContext","Error","withIAPContext","Component","WrapperComponent","props","connected","setConnected","useState","products","setProducts","promotedProductsIOS","setPromotedProductsIOS","subscriptions","setSubscriptions","purchaseHistories","setPurchaseHistories","availablePurchases","setAvailablePurchases","currentPurchase","setCurrentPurchase","currentPurchaseError","setCurrentPurchaseError","initConnectionError","setInitConnectionError","context","useMemo","useEffect","initConnection","then","value","undefined","catch","purchaseUpdateSubscription","purchaseUpdatedListener","purchase","purchaseErrorSubscription","purchaseErrorListener","error","promotedProductSubscription","promotedProductListener","product","getPromotedProductIOS","prevProducts","remove"],"sources":["withIAPContext.tsx"],"sourcesContent":["import React, {useContext, useEffect, useMemo, useState} from 'react';\n\nimport {\n getPromotedProductIOS,\n initConnection,\n promotedProductListener,\n purchaseErrorListener,\n purchaseUpdatedListener,\n} from '../iap';\nimport type {\n InAppPurchase,\n Product,\n Purchase,\n PurchaseError,\n Subscription,\n SubscriptionPurchase,\n} from '../types';\n\ntype IAPContextType = {\n connected: boolean;\n products: Product[];\n promotedProductsIOS: Product[];\n subscriptions: Subscription[];\n purchaseHistories: Purchase[];\n availablePurchases: Purchase[];\n currentPurchase?: Purchase;\n currentPurchaseError?: PurchaseError;\n initConnectionError?: Error;\n setProducts: (products: Product[]) => void;\n setSubscriptions: (subscriptions: Subscription[]) => void;\n setPurchaseHistories: (purchaseHistories: Purchase[]) => void;\n setAvailablePurchases: (availablePurchases: Purchase[]) => void;\n setCurrentPurchase: (currentPurchase: Purchase | undefined) => void;\n setCurrentPurchaseError: (\n currentPurchaseError: PurchaseError | undefined,\n ) => void;\n};\n\n// @ts-ignore\nconst IAPContext = React.createContext<IAPContextType>(null);\n\nexport function useIAPContext(): IAPContextType {\n const ctx = useContext(IAPContext);\n\n if (!ctx) {\n throw new Error('You need wrap your app with withIAPContext HOC');\n }\n\n return ctx;\n}\n\nexport function withIAPContext<T>(Component: React.ComponentType<T>) {\n return function WrapperComponent(props: T) {\n const [connected, setConnected] = useState(false);\n const [products, setProducts] = useState<Product[]>([]);\n\n const [promotedProductsIOS, setPromotedProductsIOS] = useState<Product[]>(\n [],\n );\n const [subscriptions, setSubscriptions] = useState<Subscription[]>([]);\n const [purchaseHistories, setPurchaseHistories] = useState<Purchase[]>([]);\n\n const [availablePurchases, setAvailablePurchases] = useState<Purchase[]>(\n [],\n );\n const [currentPurchase, setCurrentPurchase] = useState<Purchase>();\n\n const [currentPurchaseError, setCurrentPurchaseError] =\n useState<PurchaseError>();\n\n const [initConnectionError, setInitConnectionError] = useState<Error>();\n\n const context = useMemo(\n () => ({\n connected,\n products,\n subscriptions,\n promotedProductsIOS,\n purchaseHistories,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n initConnectionError,\n setProducts,\n setSubscriptions,\n setPurchaseHistories,\n setAvailablePurchases,\n setCurrentPurchase,\n setCurrentPurchaseError,\n }),\n [\n connected,\n products,\n subscriptions,\n promotedProductsIOS,\n purchaseHistories,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n initConnectionError,\n setProducts,\n setSubscriptions,\n setPurchaseHistories,\n setAvailablePurchases,\n setCurrentPurchase,\n setCurrentPurchaseError,\n ],\n );\n\n useEffect(() => {\n initConnection()\n .then((value) => {\n setInitConnectionError(undefined);\n setConnected(value);\n })\n .catch(setInitConnectionError);\n }, []);\n\n useEffect(() => {\n if (!connected) {\n return;\n }\n\n const purchaseUpdateSubscription = purchaseUpdatedListener(\n async (purchase: InAppPurchase | SubscriptionPurchase) => {\n setCurrentPurchaseError(undefined);\n setCurrentPurchase(purchase);\n },\n );\n\n const purchaseErrorSubscription = purchaseErrorListener(\n (error: PurchaseError) => {\n setCurrentPurchase(undefined);\n setCurrentPurchaseError(error);\n },\n );\n\n const promotedProductSubscription = promotedProductListener(async () => {\n const product = await getPromotedProductIOS();\n\n setPromotedProductsIOS((prevProducts) => [\n ...prevProducts,\n ...(product ? [product] : []),\n ]);\n });\n\n return () => {\n purchaseUpdateSubscription.remove();\n purchaseErrorSubscription.remove();\n promotedProductSubscription
|
|
1
|
+
{"version":3,"names":["IAPContext","React","createContext","useIAPContext","ctx","useContext","Error","withIAPContext","Component","WrapperComponent","props","connected","setConnected","useState","products","setProducts","promotedProductsIOS","setPromotedProductsIOS","subscriptions","setSubscriptions","purchaseHistories","setPurchaseHistories","availablePurchases","setAvailablePurchases","currentPurchase","setCurrentPurchase","currentPurchaseError","setCurrentPurchaseError","initConnectionError","setInitConnectionError","context","useMemo","useEffect","initConnection","then","value","undefined","catch","purchaseUpdateSubscription","purchaseUpdatedListener","purchase","purchaseErrorSubscription","purchaseErrorListener","error","promotedProductSubscription","promotedProductListener","product","getPromotedProductIOS","prevProducts","remove"],"sources":["withIAPContext.tsx"],"sourcesContent":["import React, {useContext, useEffect, useMemo, useState} from 'react';\n\nimport {\n getPromotedProductIOS,\n initConnection,\n promotedProductListener,\n purchaseErrorListener,\n purchaseUpdatedListener,\n} from '../iap';\nimport type {\n InAppPurchase,\n Product,\n Purchase,\n PurchaseError,\n Subscription,\n SubscriptionPurchase,\n} from '../types';\n\ntype IAPContextType = {\n connected: boolean;\n products: Product[];\n promotedProductsIOS: Product[];\n subscriptions: Subscription[];\n purchaseHistories: Purchase[];\n availablePurchases: Purchase[];\n currentPurchase?: Purchase;\n currentPurchaseError?: PurchaseError;\n initConnectionError?: Error;\n setProducts: (products: Product[]) => void;\n setSubscriptions: (subscriptions: Subscription[]) => void;\n setPurchaseHistories: (purchaseHistories: Purchase[]) => void;\n setAvailablePurchases: (availablePurchases: Purchase[]) => void;\n setCurrentPurchase: (currentPurchase: Purchase | undefined) => void;\n setCurrentPurchaseError: (\n currentPurchaseError: PurchaseError | undefined,\n ) => void;\n};\n\n// @ts-ignore\nconst IAPContext = React.createContext<IAPContextType>(null);\n\nexport function useIAPContext(): IAPContextType {\n const ctx = useContext(IAPContext);\n\n if (!ctx) {\n throw new Error('You need wrap your app with withIAPContext HOC');\n }\n\n return ctx;\n}\n\nexport function withIAPContext<T>(Component: React.ComponentType<T>) {\n return function WrapperComponent(props: T) {\n const [connected, setConnected] = useState(false);\n const [products, setProducts] = useState<Product[]>([]);\n\n const [promotedProductsIOS, setPromotedProductsIOS] = useState<Product[]>(\n [],\n );\n const [subscriptions, setSubscriptions] = useState<Subscription[]>([]);\n const [purchaseHistories, setPurchaseHistories] = useState<Purchase[]>([]);\n\n const [availablePurchases, setAvailablePurchases] = useState<Purchase[]>(\n [],\n );\n const [currentPurchase, setCurrentPurchase] = useState<Purchase>();\n\n const [currentPurchaseError, setCurrentPurchaseError] =\n useState<PurchaseError>();\n\n const [initConnectionError, setInitConnectionError] = useState<Error>();\n\n const context = useMemo(\n () => ({\n connected,\n products,\n subscriptions,\n promotedProductsIOS,\n purchaseHistories,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n initConnectionError,\n setProducts,\n setSubscriptions,\n setPurchaseHistories,\n setAvailablePurchases,\n setCurrentPurchase,\n setCurrentPurchaseError,\n }),\n [\n connected,\n products,\n subscriptions,\n promotedProductsIOS,\n purchaseHistories,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n initConnectionError,\n setProducts,\n setSubscriptions,\n setPurchaseHistories,\n setAvailablePurchases,\n setCurrentPurchase,\n setCurrentPurchaseError,\n ],\n );\n\n useEffect(() => {\n initConnection()\n .then((value) => {\n setInitConnectionError(undefined);\n setConnected(value);\n })\n .catch(setInitConnectionError);\n }, []);\n\n useEffect(() => {\n if (!connected) {\n return;\n }\n\n const purchaseUpdateSubscription = purchaseUpdatedListener(\n async (purchase: InAppPurchase | SubscriptionPurchase) => {\n setCurrentPurchaseError(undefined);\n setCurrentPurchase(purchase);\n },\n );\n\n const purchaseErrorSubscription = purchaseErrorListener(\n (error: PurchaseError) => {\n setCurrentPurchase(undefined);\n setCurrentPurchaseError(error);\n },\n );\n\n const promotedProductSubscription = promotedProductListener(async () => {\n const product = await getPromotedProductIOS();\n\n setPromotedProductsIOS((prevProducts) => [\n ...prevProducts,\n ...(product ? [product] : []),\n ]);\n });\n\n return () => {\n purchaseUpdateSubscription.remove();\n purchaseErrorSubscription.remove();\n promotedProductSubscription?.remove();\n };\n }, [connected]);\n\n return (\n <IAPContext.Provider value={context}>\n <Component {...props} />\n </IAPContext.Provider>\n );\n };\n}\n"],"mappings":"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"}
|
package/lib/commonjs/iap.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.validateReceiptIos = exports.validateReceiptAndroid = exports.validateReceiptAmazon = exports.setAndroidNativeModule = exports.requestSubscription = exports.requestPurchaseWithQuantityIOS = exports.requestPurchaseWithOfferIOS = exports.requestPurchase = exports.purchaseUpdatedListener = exports.purchaseErrorListener = exports.promotedProductListener = exports.presentCodeRedemptionSheetIOS = exports.initConnection = exports.getSubscriptions = exports.getPurchaseHistory = exports.getPromotedProductIOS = exports.getProducts = exports.getPendingPurchasesIOS = exports.getInstallSourceAndroid = exports.getAvailablePurchases = exports.flushFailedPurchasesCachedAsPendingAndroid = exports.finishTransaction = exports.endConnection = exports.deepLinkToSubscriptionsAndroid = exports.clearTransactionIOS = exports.clearProductsIOS = exports.buyPromotedProductIOS = exports.acknowledgePurchaseAndroid = void 0;
|
|
6
|
+
exports.validateReceiptIos = exports.validateReceiptAndroid = exports.validateReceiptAmazon = exports.setAndroidNativeModule = exports.requestSubscription = exports.requestPurchaseWithQuantityIOS = exports.requestPurchaseWithOfferIOS = exports.requestPurchase = exports.purchaseUpdatedListener = exports.purchaseErrorListener = exports.promotedProductListener = exports.presentCodeRedemptionSheetIOS = exports.initConnection = exports.getSubscriptions = exports.getReceiptIOS = exports.getPurchaseHistory = exports.getPromotedProductIOS = exports.getProducts = exports.getPendingPurchasesIOS = exports.getInstallSourceAndroid = exports.getAvailablePurchases = exports.flushFailedPurchasesCachedAsPendingAndroid = exports.finishTransaction = exports.endConnection = exports.deepLinkToSubscriptionsAndroid = exports.clearTransactionIOS = exports.clearProductsIOS = exports.buyPromotedProductIOS = exports.acknowledgePurchaseAndroid = exports.IapError = void 0;
|
|
7
7
|
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
|
|
@@ -17,9 +17,23 @@ const {
|
|
|
17
17
|
RNIapAmazonModule
|
|
18
18
|
} = _reactNative.NativeModules;
|
|
19
19
|
const isAndroid = _reactNative.Platform.OS === 'android';
|
|
20
|
+
const isAmazon = isAndroid && !!RNIapAmazonModule;
|
|
21
|
+
const isIos = _reactNative.Platform.OS === 'ios';
|
|
20
22
|
const ANDROID_ITEM_TYPE_SUBSCRIPTION = 'subs';
|
|
21
23
|
const ANDROID_ITEM_TYPE_IAP = 'inapp';
|
|
22
24
|
|
|
25
|
+
class IapError {
|
|
26
|
+
constructor(code, message) {
|
|
27
|
+
this.code = code;
|
|
28
|
+
this.message = message;
|
|
29
|
+
this.code = code;
|
|
30
|
+
this.message = message;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.IapError = IapError;
|
|
36
|
+
|
|
23
37
|
const getInstallSourceAndroid = () => {
|
|
24
38
|
return RNIapModule ? _types.InstallSourceAndroid.GOOGLE_PLAY : _types.InstallSourceAndroid.AMAZON;
|
|
25
39
|
};
|
|
@@ -207,6 +221,8 @@ const getAvailablePurchases = () => (_reactNative.Platform.select({
|
|
|
207
221
|
* @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.
|
|
208
222
|
* @param {string} [obfuscatedAccountIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
|
|
209
223
|
* @param {string} [obfuscatedProfileIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
|
|
224
|
+
* @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
|
|
225
|
+
* @param {boolean} [isOfferPersonalized] Defaults to false, Only for Android V5
|
|
210
226
|
* @returns {Promise<InAppPurchase>}
|
|
211
227
|
*/
|
|
212
228
|
|
|
@@ -219,7 +235,11 @@ const requestPurchase = _ref => {
|
|
|
219
235
|
andDangerouslyFinishTransactionAutomaticallyIOS = false,
|
|
220
236
|
obfuscatedAccountIdAndroid,
|
|
221
237
|
obfuscatedProfileIdAndroid,
|
|
222
|
-
applicationUsername
|
|
238
|
+
applicationUsername,
|
|
239
|
+
skus,
|
|
240
|
+
// Android Billing V5
|
|
241
|
+
isOfferPersonalized = undefined // Android Billing V5
|
|
242
|
+
|
|
223
243
|
} = _ref;
|
|
224
244
|
return (_reactNative.Platform.select({
|
|
225
245
|
ios: async () => {
|
|
@@ -230,7 +250,7 @@ const requestPurchase = _ref => {
|
|
|
230
250
|
return getIosModule().buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, applicationUsername);
|
|
231
251
|
},
|
|
232
252
|
android: async () => {
|
|
233
|
-
return getAndroidModule().buyItemByType(ANDROID_ITEM_TYPE_IAP, [sku], null, -1, obfuscatedAccountIdAndroid, obfuscatedProfileIdAndroid, undefined);
|
|
253
|
+
return getAndroidModule().buyItemByType(ANDROID_ITEM_TYPE_IAP, skus !== null && skus !== void 0 && skus.length ? skus : [sku], null, -1, obfuscatedAccountIdAndroid, obfuscatedProfileIdAndroid, undefined, isOfferPersonalized ?? false);
|
|
234
254
|
}
|
|
235
255
|
}) || Promise.resolve)();
|
|
236
256
|
};
|
|
@@ -243,7 +263,7 @@ const requestPurchase = _ref => {
|
|
|
243
263
|
* @param {ProrationModesAndroid} [prorationModeAndroid] UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, IMMEDIATE_WITH_TIME_PRORATION, IMMEDIATE_AND_CHARGE_PRORATED_PRICE, IMMEDIATE_WITHOUT_PRORATION, DEFERRED
|
|
244
264
|
* @param {string} [obfuscatedAccountIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's account in your app.
|
|
245
265
|
* @param {string} [obfuscatedProfileIdAndroid] Specifies an optional obfuscated string that is uniquely associated with the user's profile in your app.
|
|
246
|
-
* @param {
|
|
266
|
+
* @param {SubscriptionOffers[]} [subscriptionOffers] Array of SubscriptionOffers. Every sku must be paired with a corresponding offerToken
|
|
247
267
|
* @returns {Promise<SubscriptionPurchase | null>} Promise resolves to null when using proratioModesAndroid=DEFERRED, and to a SubscriptionPurchase otherwise
|
|
248
268
|
*/
|
|
249
269
|
|
|
@@ -258,9 +278,9 @@ const requestSubscription = _ref2 => {
|
|
|
258
278
|
prorationModeAndroid = -1,
|
|
259
279
|
obfuscatedAccountIdAndroid,
|
|
260
280
|
obfuscatedProfileIdAndroid,
|
|
261
|
-
|
|
281
|
+
subscriptionOffers = undefined,
|
|
262
282
|
// Android Billing V5
|
|
263
|
-
|
|
283
|
+
isOfferPersonalized = undefined,
|
|
264
284
|
// Android Billing V5
|
|
265
285
|
applicationUsername
|
|
266
286
|
} = _ref2;
|
|
@@ -273,7 +293,16 @@ const requestSubscription = _ref2 => {
|
|
|
273
293
|
return getIosModule().buyProduct(sku, andDangerouslyFinishTransactionAutomaticallyIOS, applicationUsername);
|
|
274
294
|
},
|
|
275
295
|
android: async () => {
|
|
276
|
-
|
|
296
|
+
if (isAmazon) {
|
|
297
|
+
return RNIapAmazonModule.buyItemByType(sku);
|
|
298
|
+
} else {
|
|
299
|
+
if (!(subscriptionOffers !== null && subscriptionOffers !== void 0 && subscriptionOffers.length)) {
|
|
300
|
+
Promise.reject('subscriptionOffers are required for Google Play Subscriptions');
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return RNIapModule.buyItemByType(ANDROID_ITEM_TYPE_SUBSCRIPTION, subscriptionOffers === null || subscriptionOffers === void 0 ? void 0 : subscriptionOffers.map(so => so.sku), purchaseTokenAndroid, prorationModeAndroid, obfuscatedAccountIdAndroid, obfuscatedProfileIdAndroid, subscriptionOffers === null || subscriptionOffers === void 0 ? void 0 : subscriptionOffers.map(so => so.offerToken), isOfferPersonalized ?? false);
|
|
305
|
+
}
|
|
277
306
|
}
|
|
278
307
|
}) || Promise.resolve)();
|
|
279
308
|
};
|
|
@@ -560,7 +589,13 @@ const purchaseErrorListener = listener => new _reactNative.NativeEventEmitter(ge
|
|
|
560
589
|
|
|
561
590
|
exports.purchaseErrorListener = purchaseErrorListener;
|
|
562
591
|
|
|
563
|
-
const promotedProductListener = listener =>
|
|
592
|
+
const promotedProductListener = listener => {
|
|
593
|
+
if (isIos) {
|
|
594
|
+
return new _reactNative.NativeEventEmitter(getIosModule()).addListener('iap-promoted-product', listener);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
return null;
|
|
598
|
+
};
|
|
564
599
|
/**
|
|
565
600
|
* Get the current receipt base64 encoded in IOS.
|
|
566
601
|
* @param {forceRefresh?:boolean}
|
|
@@ -571,13 +606,23 @@ const promotedProductListener = listener => new _reactNative.NativeEventEmitter(
|
|
|
571
606
|
exports.promotedProductListener = promotedProductListener;
|
|
572
607
|
|
|
573
608
|
const getPendingPurchasesIOS = async () => getIosModule().getPendingTransactions();
|
|
609
|
+
/**
|
|
610
|
+
* Get the current receipt base64 encoded in IOS.
|
|
611
|
+
* @param {forceRefresh?:boolean}
|
|
612
|
+
* @returns {Promise<string>}
|
|
613
|
+
*/
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
exports.getPendingPurchasesIOS = getPendingPurchasesIOS;
|
|
617
|
+
|
|
618
|
+
const getReceiptIOS = async forceRefresh => getIosModule().requestReceipt(forceRefresh ?? false);
|
|
574
619
|
/**
|
|
575
620
|
* Launches a modal to register the redeem offer code in IOS.
|
|
576
621
|
* @returns {Promise<null>}
|
|
577
622
|
*/
|
|
578
623
|
|
|
579
624
|
|
|
580
|
-
exports.
|
|
625
|
+
exports.getReceiptIOS = getReceiptIOS;
|
|
581
626
|
|
|
582
627
|
const presentCodeRedemptionSheetIOS = async () => getIosModule().presentCodeRedemptionSheet();
|
|
583
628
|
|