react-native-iap 9.0.0-beta → 9.0.0-beta12
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 +11 -22
- package/RNIap.podspec +33 -18
- package/android/build.gradle +137 -38
- package/android/gradle.properties +8 -0
- package/android/src/play/java/com/dooboolab/RNIap/RNIapModule.kt +99 -89
- package/android/src/play/java/com/dooboolab/RNIap/RNIapPackage.kt +0 -1
- package/android/src/testPlay/java/com/dooboolab/RNIap/{RNIapModuleTestV4.kt → RNIapModuleTest.kt} +47 -35
- package/ios/RNIapIos-Bridging-Header.h +2 -0
- package/ios/RNIapIos.m +14 -1
- package/ios/RNIapIos.swift +903 -883
- package/ios/{RNIap.xcodeproj → RNIapIos.xcodeproj}/project.pbxproj +29 -116
- package/lib/commonjs/__test__/iap.test.js +21 -0
- package/lib/commonjs/__test__/iap.test.js.map +1 -0
- package/lib/commonjs/hooks/useIAP.js +78 -0
- package/lib/commonjs/hooks/useIAP.js.map +1 -0
- package/lib/commonjs/hooks/withIAPContext.js +92 -0
- package/lib/commonjs/hooks/withIAPContext.js.map +1 -0
- package/lib/commonjs/iap.js +586 -0
- package/lib/commonjs/iap.js.map +1 -0
- package/lib/commonjs/index.js +59 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/types/amazon.js +2 -0
- package/lib/commonjs/types/amazon.js.map +1 -0
- package/lib/commonjs/types/android.js +55 -0
- package/lib/commonjs/types/android.js.map +1 -0
- package/lib/commonjs/types/apple.js +165 -0
- package/lib/commonjs/types/apple.js.map +1 -0
- package/lib/commonjs/types/index.js +59 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/module/__test__/iap.test.js +17 -0
- package/lib/module/__test__/iap.test.js.map +1 -0
- package/lib/module/hooks/useIAP.js +68 -0
- package/lib/module/hooks/useIAP.js.map +1 -0
- package/lib/module/hooks/withIAPContext.js +76 -0
- package/lib/module/hooks/withIAPContext.js.map +1 -0
- package/lib/module/iap.js +494 -0
- package/lib/module/iap.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types/amazon.js +2 -0
- package/lib/module/types/amazon.js.map +1 -0
- package/lib/module/types/android.js +44 -0
- package/lib/module/types/android.js.map +1 -0
- package/lib/module/types/apple.js +153 -0
- package/lib/module/types/apple.js.map +1 -0
- package/lib/module/types/index.js +48 -0
- package/lib/module/types/index.js.map +1 -0
- package/{src → lib/typescript}/__test__/iap.test.d.ts +0 -0
- package/{src → lib/typescript}/hooks/useIAP.d.ts +1 -1
- package/{src → lib/typescript}/hooks/withIAPContext.d.ts +1 -1
- package/{src → lib/typescript}/iap.d.ts +17 -12
- package/{src → lib/typescript}/index.d.ts +2 -1
- package/{src → lib/typescript}/types/amazon.d.ts +0 -0
- package/{src → lib/typescript}/types/android.d.ts +0 -0
- package/{src → lib/typescript}/types/apple.d.ts +0 -0
- package/{src → lib/typescript}/types/index.d.ts +35 -22
- package/package.json +87 -57
- package/src/__test__/iap.test.ts +20 -0
- package/src/hooks/useIAP.ts +130 -0
- package/src/hooks/withIAPContext.tsx +160 -0
- package/src/iap.ts +700 -0
- package/src/{index.js → index.ts} +4 -1
- package/src/types/amazon.ts +23 -0
- package/src/types/android.ts +51 -0
- package/src/types/apple.ts +467 -0
- package/src/types/index.ts +185 -0
- package/.editorconfig +0 -10
- package/.flowconfig +0 -11
- package/.monolinterrc +0 -3
- package/.yarn/install-state.gz +0 -0
- package/.yarn/releases/yarn-3.2.0.cjs +0 -785
- package/.yarnrc.yml +0 -3
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
- package/android/gradlew +0 -160
- package/android/gradlew.bat +0 -90
- package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleInterface.kt +0 -44
- package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleV4.kt +0 -656
- package/babel.config.js +0 -10
- package/index.d.ts +0 -3
- package/index.js +0 -3
- package/index.js.flow +0 -9
- package/ios/RNIap.xcodeproj/xcshareddata/xcschemes/RNIap.xcscheme +0 -80
- package/ios/RNIapQueue.swift +0 -36
- package/jest.config.js +0 -194
- package/src/__test__/iap.test.js +0 -59
- package/src/hooks/useIAP.js +0 -141
- package/src/hooks/withIAPContext.js +0 -150
- package/src/iap.js +0 -640
- package/src/types/amazon.js +0 -1
- package/src/types/android.js +0 -22
- package/src/types/apple.js +0 -165
- package/src/types/index.js +0 -40
- package/test/mocks/react-native-modules.js +0 -14
|
@@ -26,6 +26,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
|
26
26
|
import com.facebook.react.bridge.ReactMethod
|
|
27
27
|
import com.facebook.react.bridge.ReadableArray
|
|
28
28
|
import com.facebook.react.bridge.ReadableType
|
|
29
|
+
import com.facebook.react.bridge.WritableArray
|
|
29
30
|
import com.facebook.react.bridge.WritableMap
|
|
30
31
|
import com.facebook.react.bridge.WritableNativeArray
|
|
31
32
|
import com.facebook.react.bridge.WritableNativeMap
|
|
@@ -40,8 +41,7 @@ class RNIapModule(
|
|
|
40
41
|
private val googleApiAvailability: GoogleApiAvailability = GoogleApiAvailability.getInstance()
|
|
41
42
|
) :
|
|
42
43
|
ReactContextBaseJavaModule(reactContext),
|
|
43
|
-
PurchasesUpdatedListener
|
|
44
|
-
RNIapModuleInterface {
|
|
44
|
+
PurchasesUpdatedListener {
|
|
45
45
|
|
|
46
46
|
private var billingClientCache: BillingClient? = null
|
|
47
47
|
private val skus: MutableMap<String, ProductDetails> = mutableMapOf()
|
|
@@ -49,7 +49,7 @@ class RNIapModule(
|
|
|
49
49
|
return TAG
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
fun ensureConnection(
|
|
53
53
|
promise: Promise,
|
|
54
54
|
callback: (billingClient: BillingClient) -> Unit
|
|
55
55
|
) {
|
|
@@ -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 ->
|
|
@@ -201,10 +201,12 @@ class RNIapModule(
|
|
|
201
201
|
for (i in 0 until skuArr.size()) {
|
|
202
202
|
if (skuArr.getType(i) == ReadableType.String) {
|
|
203
203
|
val sku = skuArr.getString(i)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
.
|
|
207
|
-
|
|
204
|
+
sku?.let {
|
|
205
|
+
skuList.add(
|
|
206
|
+
QueryProductDetailsParams.Product.newBuilder().setProductId(sku)
|
|
207
|
+
.setProductType(type).build()
|
|
208
|
+
)
|
|
209
|
+
}
|
|
208
210
|
}
|
|
209
211
|
}
|
|
210
212
|
val params = QueryProductDetailsParams.newBuilder().setProductList(skuList)
|
|
@@ -304,7 +306,7 @@ class RNIapModule(
|
|
|
304
306
|
}
|
|
305
307
|
|
|
306
308
|
@ReactMethod
|
|
307
|
-
|
|
309
|
+
fun getAvailableItemsByType(type: String, promise: Promise) {
|
|
308
310
|
ensureConnection(
|
|
309
311
|
promise
|
|
310
312
|
) { billingClient ->
|
|
@@ -315,42 +317,42 @@ class RNIapModule(
|
|
|
315
317
|
).build()
|
|
316
318
|
) { billingResult: BillingResult, purchases: List<Purchase>? ->
|
|
317
319
|
if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
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)
|
|
346
|
+
}
|
|
347
|
+
items.pushMap(item)
|
|
345
348
|
}
|
|
346
|
-
}
|
|
347
349
|
promise.safeResolve(items)
|
|
348
350
|
}
|
|
349
351
|
}
|
|
350
352
|
}
|
|
351
353
|
|
|
352
354
|
@ReactMethod
|
|
353
|
-
|
|
355
|
+
fun getPurchaseHistoryByType(type: String, promise: Promise) {
|
|
354
356
|
ensureConnection(
|
|
355
357
|
promise
|
|
356
358
|
) { billingClient ->
|
|
@@ -368,6 +370,9 @@ class RNIapModule(
|
|
|
368
370
|
purchaseHistoryRecordList?.forEach { purchase ->
|
|
369
371
|
val item = Arguments.createMap()
|
|
370
372
|
item.putString("productId", purchase.products[0])
|
|
373
|
+
val products = Arguments.createArray()
|
|
374
|
+
purchase.products.forEach { products.pushString(it) }
|
|
375
|
+
item.putArray("productIds", products)
|
|
371
376
|
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
372
377
|
item.putString("transactionReceipt", purchase.originalJson)
|
|
373
378
|
item.putString("purchaseToken", purchase.purchaseToken)
|
|
@@ -382,14 +387,14 @@ class RNIapModule(
|
|
|
382
387
|
}
|
|
383
388
|
|
|
384
389
|
@ReactMethod
|
|
385
|
-
|
|
390
|
+
fun buyItemByType(
|
|
386
391
|
type: String,
|
|
387
|
-
|
|
392
|
+
skuArr: ReadableArray,
|
|
388
393
|
purchaseToken: String?,
|
|
389
|
-
prorationMode: Int
|
|
394
|
+
prorationMode: Int,
|
|
390
395
|
obfuscatedAccountId: String?,
|
|
391
396
|
obfuscatedProfileId: String?,
|
|
392
|
-
|
|
397
|
+
selectedOfferIndices: ReadableArray, // New optional parameter in V5
|
|
393
398
|
promise: Promise
|
|
394
399
|
) {
|
|
395
400
|
val activity = currentActivity
|
|
@@ -404,32 +409,36 @@ class RNIapModule(
|
|
|
404
409
|
PROMISE_BUY_ITEM,
|
|
405
410
|
promise
|
|
406
411
|
)
|
|
407
|
-
val
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
412
|
+
val productParamsList =
|
|
413
|
+
skuArr.toArrayList().map { it.toString() }.mapIndexed{ index,sku ->
|
|
414
|
+
val selectedSku: ProductDetails? = skus[sku]
|
|
415
|
+
if (selectedSku == null) {
|
|
416
|
+
val debugMessage =
|
|
417
|
+
"The sku was not found. Please fetch products first by calling getItems"
|
|
418
|
+
val error = Arguments.createMap()
|
|
419
|
+
error.putString("debugMessage", debugMessage)
|
|
420
|
+
error.putString("code", PROMISE_BUY_ITEM)
|
|
421
|
+
error.putString("message", debugMessage)
|
|
422
|
+
error.putString("productId", sku)
|
|
423
|
+
sendEvent(reactContext, "purchase-error", error)
|
|
424
|
+
promise.safeReject(PROMISE_BUY_ITEM, debugMessage)
|
|
425
|
+
return@ensureConnection
|
|
426
|
+
}
|
|
427
|
+
var productParams = BillingFlowParams.ProductDetailsParams.newBuilder().setProductDetails(selectedSku)
|
|
428
|
+
val selectedOfferIndex = selectedOfferIndices.getInt(index)
|
|
429
|
+
if (selectedOfferIndex > -1 && (
|
|
430
|
+
selectedSku.subscriptionOfferDetails?.size
|
|
431
|
+
?: 0
|
|
432
|
+
) > selectedOfferIndex
|
|
433
|
+
) {
|
|
434
|
+
val offerToken =
|
|
435
|
+
selectedSku.subscriptionOfferDetails?.get(selectedOfferIndex)?.offerToken
|
|
436
|
+
offerToken?.let { productParams = productParams.setOfferToken(offerToken) }
|
|
437
|
+
}
|
|
438
|
+
productParams.build()
|
|
430
439
|
}
|
|
431
|
-
|
|
432
|
-
builder.setProductDetailsParamsList(
|
|
440
|
+
val builder = BillingFlowParams.newBuilder()
|
|
441
|
+
builder.setProductDetailsParamsList(productParamsList)
|
|
433
442
|
val subscriptionUpdateParamsBuilder = SubscriptionUpdateParams.newBuilder()
|
|
434
443
|
if (purchaseToken != null) {
|
|
435
444
|
subscriptionUpdateParamsBuilder.setOldPurchaseToken(purchaseToken)
|
|
@@ -440,14 +449,14 @@ class RNIapModule(
|
|
|
440
449
|
if (obfuscatedProfileId != null) {
|
|
441
450
|
builder.setObfuscatedProfileId(obfuscatedProfileId)
|
|
442
451
|
}
|
|
443
|
-
if (prorationMode !=
|
|
452
|
+
if (prorationMode != -1) {
|
|
444
453
|
if (prorationMode
|
|
445
454
|
== BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
446
455
|
) {
|
|
447
456
|
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
448
457
|
BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
449
458
|
)
|
|
450
|
-
if (type != BillingClient.
|
|
459
|
+
if (type != BillingClient.ProductType.SUBS) {
|
|
451
460
|
val debugMessage =
|
|
452
461
|
(
|
|
453
462
|
"IMMEDIATE_AND_CHARGE_PRORATED_PRICE for proration mode only works in" +
|
|
@@ -457,7 +466,7 @@ class RNIapModule(
|
|
|
457
466
|
error.putString("debugMessage", debugMessage)
|
|
458
467
|
error.putString("code", PROMISE_BUY_ITEM)
|
|
459
468
|
error.putString("message", debugMessage)
|
|
460
|
-
error.
|
|
469
|
+
error.putArray("productIds", skuArr)
|
|
461
470
|
sendEvent(reactContext, "purchase-error", error)
|
|
462
471
|
promise.safeReject(PROMISE_BUY_ITEM, debugMessage)
|
|
463
472
|
return@ensureConnection
|
|
@@ -508,7 +517,7 @@ class RNIapModule(
|
|
|
508
517
|
}
|
|
509
518
|
|
|
510
519
|
@ReactMethod
|
|
511
|
-
|
|
520
|
+
fun acknowledgePurchase(
|
|
512
521
|
token: String,
|
|
513
522
|
developerPayLoad: String?,
|
|
514
523
|
promise: Promise
|
|
@@ -538,7 +547,7 @@ class RNIapModule(
|
|
|
538
547
|
}
|
|
539
548
|
|
|
540
549
|
@ReactMethod
|
|
541
|
-
|
|
550
|
+
fun consumeProduct(
|
|
542
551
|
token: String,
|
|
543
552
|
developerPayLoad: String?,
|
|
544
553
|
promise: Promise
|
|
@@ -559,6 +568,7 @@ class RNIapModule(
|
|
|
559
568
|
.getBillingResponseData(billingResult.responseCode)
|
|
560
569
|
map.putString("code", errorData[0])
|
|
561
570
|
map.putString("message", errorData[1])
|
|
571
|
+
map.putString("purchaseToken",purchaseToken)
|
|
562
572
|
promise.safeResolve(map)
|
|
563
573
|
}
|
|
564
574
|
}
|
|
@@ -579,11 +589,13 @@ class RNIapModule(
|
|
|
579
589
|
return
|
|
580
590
|
}
|
|
581
591
|
if (purchases != null) {
|
|
582
|
-
|
|
583
|
-
|
|
592
|
+
val promiseItems: WritableArray = Arguments.createArray()
|
|
593
|
+
purchases.forEach { purchase ->
|
|
584
594
|
val item = Arguments.createMap()
|
|
585
|
-
val purchase = purchases[i]
|
|
586
595
|
item.putString("productId", purchase.products[0])
|
|
596
|
+
val products = Arguments.createArray()
|
|
597
|
+
purchase.products.forEach { products.pushString(it) }
|
|
598
|
+
item.putArray("productIds", products)
|
|
587
599
|
item.putString("transactionId", purchase.orderId)
|
|
588
600
|
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
589
601
|
item.putString("transactionReceipt", purchase.originalJson)
|
|
@@ -606,13 +618,10 @@ class RNIapModule(
|
|
|
606
618
|
accountIdentifiers.obfuscatedProfileId
|
|
607
619
|
)
|
|
608
620
|
}
|
|
609
|
-
|
|
610
|
-
promiseItem.merge(item)
|
|
621
|
+
promiseItems.pushMap(item)
|
|
611
622
|
sendEvent(reactContext, "purchase-updated", item)
|
|
612
623
|
}
|
|
613
|
-
|
|
614
|
-
DoobooUtils.instance.resolvePromisesForKey(PROMISE_BUY_ITEM, promiseItem)
|
|
615
|
-
}
|
|
624
|
+
DoobooUtils.instance.resolvePromisesForKey(PROMISE_BUY_ITEM, promiseItems)
|
|
616
625
|
} else {
|
|
617
626
|
val result = Arguments.createMap()
|
|
618
627
|
result.putInt("responseCode", billingResult.responseCode)
|
|
@@ -649,22 +658,22 @@ class RNIapModule(
|
|
|
649
658
|
}
|
|
650
659
|
|
|
651
660
|
@ReactMethod
|
|
652
|
-
|
|
661
|
+
fun startListening(promise: Promise) {
|
|
653
662
|
sendUnconsumedPurchases(promise)
|
|
654
663
|
}
|
|
655
664
|
|
|
656
665
|
@ReactMethod
|
|
657
|
-
|
|
666
|
+
fun addListener(eventName: String) {
|
|
658
667
|
// Keep: Required for RN built-in Event Emitter Calls.
|
|
659
668
|
}
|
|
660
669
|
|
|
661
670
|
@ReactMethod
|
|
662
|
-
|
|
671
|
+
fun removeListeners(count: Double) {
|
|
663
672
|
// Keep: Required for RN built-in Event Emitter Calls.
|
|
664
673
|
}
|
|
665
674
|
|
|
666
675
|
@ReactMethod
|
|
667
|
-
|
|
676
|
+
fun getPackageName(promise: Promise) = promise.resolve(reactApplicationContext.packageName)
|
|
668
677
|
|
|
669
678
|
private fun sendEvent(
|
|
670
679
|
reactContext: ReactContext,
|
|
@@ -687,6 +696,7 @@ class RNIapModule(
|
|
|
687
696
|
override fun onHostPause() {}
|
|
688
697
|
override fun onHostDestroy() {
|
|
689
698
|
billingClientCache?.endConnection()
|
|
699
|
+
billingClientCache = null
|
|
690
700
|
}
|
|
691
701
|
}
|
|
692
702
|
reactContext.addLifecycleEventListener(lifecycleEventListener)
|
|
@@ -15,7 +15,6 @@ class RNIapPackage : ReactPackage {
|
|
|
15
15
|
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
16
16
|
val modules: MutableList<NativeModule> = ArrayList()
|
|
17
17
|
modules.add(RNIapModule(reactContext))
|
|
18
|
-
modules.add(RNIapModuleV4(reactContext))
|
|
19
18
|
return modules
|
|
20
19
|
}
|
|
21
20
|
}
|
package/android/src/testPlay/java/com/dooboolab/RNIap/{RNIapModuleTestV4.kt → RNIapModuleTest.kt}
RENAMED
|
@@ -4,9 +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.ProductDetailsResponseListener
|
|
7
8
|
import com.android.billingclient.api.Purchase
|
|
8
9
|
import com.android.billingclient.api.PurchasesResponseListener
|
|
9
|
-
import com.android.billingclient.api.
|
|
10
|
+
import com.android.billingclient.api.QueryPurchasesParams
|
|
10
11
|
import com.facebook.react.bridge.Arguments
|
|
11
12
|
import com.facebook.react.bridge.Promise
|
|
12
13
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
@@ -30,7 +31,7 @@ import org.junit.Assert.assertTrue
|
|
|
30
31
|
import org.junit.Before
|
|
31
32
|
import org.junit.Test
|
|
32
33
|
|
|
33
|
-
class
|
|
34
|
+
class RNIapModuleTest {
|
|
34
35
|
|
|
35
36
|
@MockK
|
|
36
37
|
lateinit var context: ReactApplicationContext
|
|
@@ -44,14 +45,14 @@ class RNIapModuleTestV4 {
|
|
|
44
45
|
@MockK
|
|
45
46
|
lateinit var availability: GoogleApiAvailability
|
|
46
47
|
|
|
47
|
-
private lateinit var module:
|
|
48
|
+
private lateinit var module: RNIapModule
|
|
48
49
|
|
|
49
50
|
@Before
|
|
50
51
|
fun setUp() {
|
|
51
52
|
MockKAnnotations.init(this, relaxUnitFun = true)
|
|
52
53
|
every { builder.setListener(any()) } returns builder
|
|
53
54
|
every { builder.build() } returns billingClient
|
|
54
|
-
module =
|
|
55
|
+
module = RNIapModule(context, builder, availability)
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
@Test
|
|
@@ -134,7 +135,7 @@ class RNIapModuleTestV4 {
|
|
|
134
135
|
every { billingClient.isReady } returns true
|
|
135
136
|
val promise = mockk<Promise>(relaxed = true)
|
|
136
137
|
val listener = slot<PurchasesResponseListener>()
|
|
137
|
-
every { billingClient.queryPurchasesAsync(any<
|
|
138
|
+
every { billingClient.queryPurchasesAsync(any<QueryPurchasesParams>(), capture(listener)) } answers {
|
|
138
139
|
listener.captured.onQueryPurchasesResponse(BillingResult.newBuilder().build(), listOf())
|
|
139
140
|
}
|
|
140
141
|
module.initConnection(mockk())
|
|
@@ -150,7 +151,7 @@ class RNIapModuleTestV4 {
|
|
|
150
151
|
every { billingClient.isReady } returns true
|
|
151
152
|
val promise = mockk<Promise>(relaxed = true)
|
|
152
153
|
val listener = slot<PurchasesResponseListener>()
|
|
153
|
-
every { billingClient.queryPurchasesAsync(any<
|
|
154
|
+
every { billingClient.queryPurchasesAsync(any<QueryPurchasesParams>(), capture(listener)) } answers {
|
|
154
155
|
listener.captured.onQueryPurchasesResponse(
|
|
155
156
|
BillingResult.newBuilder().build(),
|
|
156
157
|
listOf(
|
|
@@ -207,30 +208,39 @@ class RNIapModuleTestV4 {
|
|
|
207
208
|
every { availability.isGooglePlayServicesAvailable(any()) } returns ConnectionResult.SUCCESS
|
|
208
209
|
every { billingClient.isReady } returns true
|
|
209
210
|
val promise = mockk<Promise>(relaxed = true)
|
|
210
|
-
val listener = slot<
|
|
211
|
-
every { billingClient.
|
|
212
|
-
listener.captured.
|
|
211
|
+
val listener = slot<ProductDetailsResponseListener>()
|
|
212
|
+
every { billingClient.queryProductDetailsAsync(any(), capture(listener)) } answers {
|
|
213
|
+
listener.captured.onProductDetailsResponse(
|
|
213
214
|
BillingResult.newBuilder().build(),
|
|
214
215
|
listOf(
|
|
215
216
|
mockk {
|
|
216
|
-
every {
|
|
217
|
-
|
|
218
|
-
every {
|
|
219
|
-
every {
|
|
220
|
-
|
|
221
|
-
every {
|
|
222
|
-
every {
|
|
223
|
-
every {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
every {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
217
|
+
every { productId } returns "sku1"
|
|
218
|
+
|
|
219
|
+
every { title } returns "title2"
|
|
220
|
+
every { description } returns "My product"
|
|
221
|
+
|
|
222
|
+
every { productType } returns "sub"
|
|
223
|
+
every { name } returns "name of product"
|
|
224
|
+
every { oneTimePurchaseOfferDetails } returns mockk {
|
|
225
|
+
every { priceCurrencyCode} returns "my code"
|
|
226
|
+
every {formattedPrice} returns "$20.00"
|
|
227
|
+
every { priceAmountMicros } returns 20000
|
|
228
|
+
|
|
229
|
+
}
|
|
230
|
+
every { subscriptionOfferDetails } returns listOf( mockk {
|
|
231
|
+
every { offerToken } returns "sToken"
|
|
232
|
+
every { offerTags } returns listOf("offerTag1","offerTag2")
|
|
233
|
+
every { pricingPhases} returns mockk{
|
|
234
|
+
every { pricingPhaseList } returns listOf(mockk{
|
|
235
|
+
every { formattedPrice } returns "$13.0"
|
|
236
|
+
every { priceCurrencyCode } returns "USD"
|
|
237
|
+
every { billingPeriod } returns "1 week"
|
|
238
|
+
every { billingCycleCount } returns 1
|
|
239
|
+
every { priceAmountMicros } returns 13000
|
|
240
|
+
every { recurrenceMode } returns 2
|
|
241
|
+
})
|
|
242
|
+
}
|
|
243
|
+
})
|
|
234
244
|
}
|
|
235
245
|
)
|
|
236
246
|
)
|
|
@@ -242,19 +252,21 @@ class RNIapModuleTestV4 {
|
|
|
242
252
|
}
|
|
243
253
|
mockkStatic(Arguments::class)
|
|
244
254
|
|
|
245
|
-
val itemsMap = mockk<WritableMap>()
|
|
246
|
-
val itemsArr = mockk<WritableArray>()
|
|
247
|
-
every { Arguments.createMap() } returns itemsMap
|
|
248
|
-
every { Arguments.createArray() } returns itemsArr
|
|
249
|
-
every { itemsMap.putString(any(), any()) } just runs
|
|
255
|
+
val itemsMap = mockk<WritableMap>(relaxed = true)
|
|
250
256
|
var itemsSize = 0
|
|
251
|
-
|
|
252
|
-
|
|
257
|
+
val itemsArr = mockk<WritableArray>{
|
|
258
|
+
every { pushString(any()) } just runs
|
|
259
|
+
every { pushMap(any()) } answers {
|
|
260
|
+
itemsSize++
|
|
261
|
+
}
|
|
253
262
|
}
|
|
263
|
+
every { Arguments.createMap() } returns itemsMap
|
|
264
|
+
every { Arguments.createArray() } returns itemsArr
|
|
265
|
+
|
|
254
266
|
module.initConnection(mockk())
|
|
255
267
|
module.getItemsByType("subs", skus, promise)
|
|
256
268
|
verify { promise.resolve(any()) }
|
|
257
|
-
assertEquals(
|
|
269
|
+
assertEquals(3, itemsSize)
|
|
258
270
|
}
|
|
259
271
|
|
|
260
272
|
@Test
|
package/ios/RNIapIos.m
CHANGED
|
@@ -3,23 +3,28 @@
|
|
|
3
3
|
#import <React/RCTBridgeModule.h>
|
|
4
4
|
|
|
5
5
|
@interface RCT_EXTERN_MODULE (RNIapIos, NSObject)
|
|
6
|
+
|
|
6
7
|
RCT_EXTERN_METHOD(initConnection:
|
|
7
8
|
(RCTPromiseResolveBlock)resolve
|
|
8
9
|
reject:(RCTPromiseRejectBlock)reject)
|
|
10
|
+
|
|
9
11
|
RCT_EXTERN_METHOD(endConnection:
|
|
10
12
|
(RCTPromiseResolveBlock)resolve
|
|
11
13
|
reject:(RCTPromiseRejectBlock)reject)
|
|
14
|
+
|
|
12
15
|
RCT_EXTERN_METHOD(getItems:
|
|
13
16
|
(NSArray*)skus
|
|
14
17
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
15
18
|
reject:(RCTPromiseRejectBlock)reject)
|
|
19
|
+
|
|
16
20
|
RCT_EXTERN_METHOD(getAvailableItems:
|
|
17
21
|
(RCTPromiseResolveBlock)resolve
|
|
18
22
|
reject:(RCTPromiseRejectBlock)reject)
|
|
23
|
+
|
|
19
24
|
RCT_EXTERN_METHOD(buyProduct:
|
|
20
25
|
(NSString*)sku
|
|
21
|
-
appAccountToken:(NSString*)appAccountToken
|
|
22
26
|
andDangerouslyFinishTransactionAutomatically:(BOOL)andDangerouslyFinishTransactionAutomatically
|
|
27
|
+
applicationUsername:(NSString*)applicationUsername
|
|
23
28
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
24
29
|
reject:(RCTPromiseRejectBlock)reject)
|
|
25
30
|
RCT_EXTERN_METHOD(buyProductWithOffer:
|
|
@@ -33,17 +38,22 @@ RCT_EXTERN_METHOD(buyProductWithQuantityIOS:
|
|
|
33
38
|
quantity:(NSInteger)quantity
|
|
34
39
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
35
40
|
reject:(RCTPromiseRejectBlock)reject)
|
|
41
|
+
|
|
36
42
|
RCT_EXTERN_METHOD(clearTransaction:
|
|
37
43
|
(RCTPromiseResolveBlock)resolve
|
|
38
44
|
reject:(RCTPromiseRejectBlock)reject)
|
|
45
|
+
|
|
39
46
|
RCT_EXTERN_METHOD(clearProducts:
|
|
40
47
|
(RCTPromiseResolveBlock)resolve
|
|
41
48
|
reject:(RCTPromiseRejectBlock)reject)
|
|
49
|
+
|
|
42
50
|
RCT_EXTERN_METHOD(promotedProduct:
|
|
43
51
|
(RCTPromiseResolveBlock)resolve
|
|
44
52
|
reject:(RCTPromiseRejectBlock)reject)
|
|
53
|
+
|
|
45
54
|
RCT_EXTERN_METHOD(buyPromotedProduct:(RCTPromiseResolveBlock)resolve
|
|
46
55
|
reject:(RCTPromiseRejectBlock)reject)
|
|
56
|
+
|
|
47
57
|
RCT_EXTERN_METHOD(requestReceipt:
|
|
48
58
|
(BOOL)refresh
|
|
49
59
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
@@ -52,10 +62,13 @@ RCT_EXTERN_METHOD(finishTransaction:
|
|
|
52
62
|
(NSString*)transactionIdentifier
|
|
53
63
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
54
64
|
reject:(RCTPromiseRejectBlock)reject)
|
|
65
|
+
|
|
55
66
|
RCT_EXTERN_METHOD(getPendingTransactions:
|
|
56
67
|
(RCTPromiseResolveBlock)resolve
|
|
57
68
|
reject:(RCTPromiseRejectBlock)reject)
|
|
69
|
+
|
|
58
70
|
RCT_EXTERN_METHOD(presentCodeRedemptionSheet:
|
|
59
71
|
(RCTPromiseResolveBlock)resolve
|
|
60
72
|
reject:(RCTPromiseRejectBlock)reject)
|
|
73
|
+
|
|
61
74
|
@end
|