react-native-iap 9.0.0-beta7 → 9.0.0-beta9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +4 -20
  2. package/RNIap.podspec +33 -18
  3. package/android/build.gradle +137 -38
  4. package/android/gradle.properties +8 -0
  5. package/android/src/play/java/com/dooboolab/RNIap/RNIapModule.kt +55 -54
  6. package/android/src/play/java/com/dooboolab/RNIap/RNIapPackage.kt +0 -1
  7. package/android/src/testPlay/java/com/dooboolab/RNIap/{RNIapModuleTestV4.kt → RNIapModuleTest.kt} +48 -34
  8. package/ios/RNIapIos-Bridging-Header.h +2 -0
  9. package/ios/RNIapIos.m +14 -1
  10. package/ios/RNIapIos.swift +903 -881
  11. package/ios/{RNIap.xcodeproj → RNIapIos.xcodeproj}/project.pbxproj +29 -116
  12. package/lib/commonjs/__test__/iap.test.js +21 -0
  13. package/lib/commonjs/__test__/iap.test.js.map +1 -0
  14. package/lib/commonjs/hooks/useIAP.js +78 -0
  15. package/lib/commonjs/hooks/useIAP.js.map +1 -0
  16. package/lib/commonjs/hooks/withIAPContext.js +92 -0
  17. package/lib/commonjs/hooks/withIAPContext.js.map +1 -0
  18. package/lib/commonjs/iap.js +585 -0
  19. package/lib/commonjs/iap.js.map +1 -0
  20. package/lib/commonjs/index.js +59 -0
  21. package/lib/commonjs/index.js.map +1 -0
  22. package/lib/commonjs/types/amazon.js +2 -0
  23. package/lib/commonjs/types/amazon.js.map +1 -0
  24. package/lib/commonjs/types/android.js +55 -0
  25. package/lib/commonjs/types/android.js.map +1 -0
  26. package/lib/commonjs/types/apple.js +165 -0
  27. package/lib/commonjs/types/apple.js.map +1 -0
  28. package/lib/commonjs/types/index.js +59 -0
  29. package/lib/commonjs/types/index.js.map +1 -0
  30. package/lib/module/__test__/iap.test.js +17 -0
  31. package/lib/module/__test__/iap.test.js.map +1 -0
  32. package/lib/module/hooks/useIAP.js +68 -0
  33. package/lib/module/hooks/useIAP.js.map +1 -0
  34. package/lib/module/hooks/withIAPContext.js +76 -0
  35. package/lib/module/hooks/withIAPContext.js.map +1 -0
  36. package/lib/module/iap.js +493 -0
  37. package/lib/module/iap.js.map +1 -0
  38. package/lib/module/index.js +6 -0
  39. package/lib/module/index.js.map +1 -0
  40. package/lib/module/types/amazon.js +2 -0
  41. package/lib/module/types/amazon.js.map +1 -0
  42. package/lib/module/types/android.js +44 -0
  43. package/lib/module/types/android.js.map +1 -0
  44. package/lib/module/types/apple.js +153 -0
  45. package/lib/module/types/apple.js.map +1 -0
  46. package/lib/module/types/index.js +48 -0
  47. package/lib/module/types/index.js.map +1 -0
  48. package/{src → lib/typescript}/__test__/iap.test.d.ts +0 -0
  49. package/{src → lib/typescript}/hooks/useIAP.d.ts +1 -1
  50. package/{src → lib/typescript}/hooks/withIAPContext.d.ts +1 -1
  51. package/{src → lib/typescript}/iap.d.ts +13 -11
  52. package/{src → lib/typescript}/index.d.ts +2 -1
  53. package/{src → lib/typescript}/types/amazon.d.ts +0 -0
  54. package/{src → lib/typescript}/types/android.d.ts +0 -0
  55. package/{src → lib/typescript}/types/apple.d.ts +0 -0
  56. package/{src → lib/typescript}/types/index.d.ts +23 -4
  57. package/package.json +84 -57
  58. package/src/__test__/iap.test.ts +20 -0
  59. package/src/hooks/useIAP.ts +130 -0
  60. package/src/hooks/withIAPContext.tsx +160 -0
  61. package/src/iap.ts +699 -0
  62. package/src/{index.js → index.ts} +4 -1
  63. package/src/types/amazon.ts +23 -0
  64. package/src/types/android.ts +51 -0
  65. package/src/types/apple.ts +467 -0
  66. package/src/types/index.ts +209 -0
  67. package/.editorconfig +0 -10
  68. package/.flowconfig +0 -11
  69. package/.monolinterrc +0 -3
  70. package/.prettierignore +0 -6
  71. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  72. package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
  73. package/android/gradlew +0 -160
  74. package/android/gradlew.bat +0 -90
  75. package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleInterface.kt +0 -44
  76. package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleV4.kt +0 -658
  77. package/babel.config.js +0 -12
  78. package/index.d.ts +0 -3
  79. package/index.js +0 -3
  80. package/index.js.flow +0 -9
  81. package/ios/RNIap.xcodeproj/xcshareddata/xcschemes/RNIap.xcscheme +0 -80
  82. package/jest.config.js +0 -190
  83. package/src/__test__/iap.test.js +0 -59
  84. package/src/hooks/useIAP.js +0 -141
  85. package/src/hooks/withIAPContext.js +0 -150
  86. package/src/iap.js +0 -638
  87. package/src/types/amazon.js +0 -1
  88. package/src/types/android.js +0 -22
  89. package/src/types/apple.js +0 -165
  90. package/src/types/index.js +0 -40
  91. package/test/mocks/react-native-modules.js +0 -14
@@ -1,658 +0,0 @@
1
- package com.dooboolab.RNIap
2
-
3
- import android.util.Log
4
- import com.android.billingclient.api.AcknowledgePurchaseParams
5
- import com.android.billingclient.api.BillingClient
6
- import com.android.billingclient.api.BillingClientStateListener
7
- import com.android.billingclient.api.BillingFlowParams
8
- import com.android.billingclient.api.BillingFlowParams.SubscriptionUpdateParams
9
- import com.android.billingclient.api.BillingResult
10
- import com.android.billingclient.api.ConsumeParams
11
- import com.android.billingclient.api.ConsumeResponseListener
12
- import com.android.billingclient.api.Purchase
13
- import com.android.billingclient.api.PurchasesUpdatedListener
14
- import com.android.billingclient.api.SkuDetails
15
- import com.android.billingclient.api.SkuDetailsParams
16
- import com.facebook.react.bridge.Arguments
17
- import com.facebook.react.bridge.LifecycleEventListener
18
- import com.facebook.react.bridge.Promise
19
- import com.facebook.react.bridge.PromiseImpl
20
- import com.facebook.react.bridge.ReactApplicationContext
21
- import com.facebook.react.bridge.ReactContext
22
- import com.facebook.react.bridge.ReactContextBaseJavaModule
23
- import com.facebook.react.bridge.ReactMethod
24
- import com.facebook.react.bridge.ReadableArray
25
- import com.facebook.react.bridge.ReadableType
26
- import com.facebook.react.bridge.WritableMap
27
- import com.facebook.react.bridge.WritableNativeArray
28
- import com.facebook.react.bridge.WritableNativeMap
29
- import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
30
- import com.google.android.gms.common.ConnectionResult
31
- import com.google.android.gms.common.GoogleApiAvailability
32
- import java.math.BigDecimal
33
- import java.util.ArrayList
34
-
35
- class RNIapModuleV4(
36
- private val reactContext: ReactApplicationContext,
37
- private val builder: BillingClient.Builder = BillingClient.newBuilder(reactContext).enablePendingPurchases(),
38
- private val googleApiAvailability: GoogleApiAvailability = GoogleApiAvailability.getInstance()
39
- ) :
40
- ReactContextBaseJavaModule(reactContext),
41
- PurchasesUpdatedListener,
42
- RNIapModuleInterface {
43
-
44
- private var billingClientCache: BillingClient? = null
45
- private val skus: MutableMap<String, SkuDetails> = mutableMapOf()
46
- override fun getName(): String {
47
- return TAG
48
- }
49
-
50
- fun ensureConnection(
51
- promise: Promise,
52
- callback: (billingClient: BillingClient) -> Unit
53
- ) {
54
- val billingClient = billingClientCache
55
- if (billingClient?.isReady == true) {
56
- callback(billingClient)
57
- return
58
- } else {
59
- val nested = PromiseImpl(
60
- {
61
- if (it.isNotEmpty() && it[0] is Boolean && it[0] as Boolean) {
62
- val connectedBillingClient = billingClientCache
63
- if (connectedBillingClient?.isReady == true) {
64
- callback(connectedBillingClient)
65
- } else {
66
- promise.safeReject(DoobooUtils.E_NOT_PREPARED, "Unable to auto-initialize connection")
67
- }
68
- } else {
69
- Log.i(TAG, "Incorrect parameter in resolve")
70
- }
71
- },
72
- {
73
- if (it.size > 1 && it[0] is String && it[1] is String) {
74
- promise.safeReject(
75
- it[0] as String,
76
- it[1] as String
77
- )
78
- } else {
79
- Log.i(TAG, "Incorrect parameters in reject")
80
- }
81
- }
82
- )
83
- initConnection(nested)
84
- }
85
- }
86
-
87
- @ReactMethod
88
- override fun initConnection(promise: Promise) {
89
- if (googleApiAvailability.isGooglePlayServicesAvailable(reactContext)
90
- != ConnectionResult.SUCCESS
91
- ) {
92
- Log.i(TAG, "Google Play Services are not available on this device")
93
- promise.safeReject(DoobooUtils.E_NOT_PREPARED, "Google Play Services are not available on this device")
94
- return
95
- }
96
-
97
- if (billingClientCache?.isReady == true) {
98
- Log.i(
99
- TAG,
100
- "Already initialized, you should only call initConnection() once when your app starts"
101
- )
102
- promise.safeResolve(true)
103
- return
104
- }
105
- builder.setListener(this).build().also {
106
- billingClientCache = it
107
- it.startConnection(
108
- object : BillingClientStateListener {
109
- override fun onBillingSetupFinished(billingResult: BillingResult) {
110
- if (!isValidResult(billingResult, promise)) return
111
-
112
- promise.safeResolve(true)
113
- }
114
-
115
- override fun onBillingServiceDisconnected() {
116
- Log.i(TAG, "Billing service disconnected")
117
- }
118
- }
119
- )
120
- }
121
- }
122
-
123
- @ReactMethod
124
- override fun endConnection(promise: Promise) {
125
- billingClientCache?.endConnection()
126
- billingClientCache = null
127
- promise.safeResolve(true)
128
- }
129
-
130
- private fun consumeItems(
131
- purchases: List<Purchase>,
132
- promise: Promise,
133
- expectedResponseCode: Int = BillingClient.BillingResponseCode.OK
134
- ) {
135
- for (purchase in purchases) {
136
- ensureConnection(
137
- promise
138
- ) { billingClient ->
139
- val consumeParams =
140
- ConsumeParams.newBuilder().setPurchaseToken(purchase.purchaseToken)
141
- .build()
142
- val listener =
143
- ConsumeResponseListener { billingResult: BillingResult, outToken: String? ->
144
- if (billingResult.responseCode != expectedResponseCode) {
145
- PlayUtils.instance
146
- .rejectPromiseWithBillingError(
147
- promise,
148
- billingResult.responseCode
149
- )
150
- return@ConsumeResponseListener
151
- }
152
-
153
- promise.safeResolve(true)
154
- }
155
- billingClient.consumeAsync(consumeParams, listener)
156
- }
157
- }
158
- }
159
-
160
- @ReactMethod
161
- override fun flushFailedPurchasesCachedAsPending(promise: Promise) {
162
- ensureConnection(
163
- promise
164
- ) { billingClient ->
165
- billingClient.queryPurchasesAsync(
166
- BillingClient.SkuType.INAPP
167
- ) { billingResult: BillingResult, list: List<Purchase>? ->
168
- if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
169
- if (list == null) {
170
- // No purchases found
171
- promise.safeResolve(false)
172
- return@queryPurchasesAsync
173
- }
174
- // we only want to try to consume PENDING items, in order to force cache-refresh
175
- // for them
176
- val pendingPurchases = list.filter { it.purchaseState == Purchase.PurchaseState.PENDING }
177
-
178
- if (pendingPurchases.isEmpty()) {
179
- promise.safeResolve(false)
180
- return@queryPurchasesAsync
181
- }
182
- consumeItems(
183
- pendingPurchases,
184
- promise,
185
- BillingClient.BillingResponseCode.ITEM_NOT_OWNED
186
- )
187
- }
188
- }
189
- }
190
-
191
- @ReactMethod
192
- override fun getItemsByType(type: String, skuArr: ReadableArray, promise: Promise) {
193
- ensureConnection(
194
- promise
195
- ) { billingClient ->
196
- val skuList = ArrayList<String>()
197
- for (i in 0 until skuArr.size()) {
198
- if (skuArr.getType(i) == ReadableType.String) {
199
- val sku = skuArr.getString(i)
200
- sku?.let {
201
- skuList.add(sku)
202
- }
203
- }
204
- }
205
- val params = SkuDetailsParams.newBuilder()
206
- params.setSkusList(skuList).setType(type)
207
- billingClient.querySkuDetailsAsync(
208
- params.build()
209
- ) { billingResult: BillingResult, skuDetailsList: List<SkuDetails>? ->
210
- if (!isValidResult(billingResult, promise)) return@querySkuDetailsAsync
211
-
212
- val items = Arguments.createArray()
213
- if (skuDetailsList != null) {
214
- for (skuDetails in skuDetailsList) {
215
- skus[skuDetails.sku] = skuDetails
216
-
217
- val item = Arguments.createMap()
218
- item.putString("productId", skuDetails.sku)
219
- val introductoryPriceMicros = skuDetails.introductoryPriceAmountMicros
220
- val priceAmountMicros = skuDetails.priceAmountMicros
221
- // Use valueOf instead of constructors.
222
- // See:
223
- // https://www.javaworld.com/article/2073176/caution--double-to-bigdecimal-in-java.html
224
- val priceAmount = BigDecimal.valueOf(priceAmountMicros)
225
- val introductoryPriceAmount =
226
- BigDecimal.valueOf(introductoryPriceMicros)
227
- val microUnitsDivisor = BigDecimal.valueOf(1000000)
228
- val price = priceAmount.divide(microUnitsDivisor).toString()
229
- val introductoryPriceAsAmountAndroid =
230
- introductoryPriceAmount.divide(microUnitsDivisor).toString()
231
- item.putString("price", price)
232
- item.putString("currency", skuDetails.priceCurrencyCode)
233
- item.putString("type", skuDetails.type)
234
- item.putString("localizedPrice", skuDetails.price)
235
- item.putString("title", skuDetails.title)
236
- item.putString("description", skuDetails.description)
237
- item.putString("introductoryPrice", skuDetails.introductoryPrice)
238
- item.putString("typeAndroid", skuDetails.type)
239
- item.putString("packageNameAndroid", skuDetails.zzc())
240
- item.putString("originalPriceAndroid", skuDetails.originalPrice)
241
- item.putString(
242
- "subscriptionPeriodAndroid",
243
- skuDetails.subscriptionPeriod
244
- )
245
- item.putString("freeTrialPeriodAndroid", skuDetails.freeTrialPeriod)
246
- item.putString(
247
- "introductoryPriceCyclesAndroid",
248
- skuDetails.introductoryPriceCycles.toString()
249
- )
250
- item.putString(
251
- "introductoryPricePeriodAndroid",
252
- skuDetails.introductoryPricePeriod
253
- )
254
- item.putString(
255
- "introductoryPriceAsAmountAndroid",
256
- introductoryPriceAsAmountAndroid
257
- )
258
- item.putString("iconUrl", skuDetails.iconUrl)
259
- item.putString("originalJson", skuDetails.originalJson)
260
- val originalPriceAmountMicros =
261
- BigDecimal.valueOf(skuDetails.originalPriceAmountMicros)
262
- val originalPrice =
263
- originalPriceAmountMicros.divide(microUnitsDivisor).toString()
264
- item.putString("originalPrice", originalPrice)
265
- items.pushMap(item)
266
- }
267
- }
268
- promise.safeResolve(items)
269
- }
270
- }
271
- }
272
-
273
- /**
274
- * Rejects promise with billing code if BillingResult is not OK
275
- */
276
- private fun isValidResult(
277
- billingResult: BillingResult,
278
- promise: Promise
279
- ): Boolean {
280
- Log.d(TAG, "responseCode: " + billingResult.responseCode)
281
- if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
282
- PlayUtils.instance
283
- .rejectPromiseWithBillingError(promise, billingResult.responseCode)
284
- return false
285
- }
286
- return true
287
- }
288
-
289
- @ReactMethod
290
- override fun getAvailableItemsByType(type: String, promise: Promise) {
291
- ensureConnection(
292
- promise
293
- ) { billingClient ->
294
- val items = WritableNativeArray()
295
- billingClient.queryPurchasesAsync(
296
- if (type == "subs") BillingClient.SkuType.SUBS else BillingClient.SkuType.INAPP
297
- ) { billingResult: BillingResult, purchases: List<Purchase>? ->
298
- if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
299
- if (purchases != null) {
300
- for (i in purchases.indices) {
301
- val purchase = purchases[i]
302
- val item = WritableNativeMap()
303
- item.putString("productId", purchase.skus[0])
304
- item.putString("transactionId", purchase.orderId)
305
- item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
306
- item.putString("transactionReceipt", purchase.originalJson)
307
- item.putString("orderId", purchase.orderId)
308
- item.putString("purchaseToken", purchase.purchaseToken)
309
- item.putString("developerPayloadAndroid", purchase.developerPayload)
310
- item.putString("signatureAndroid", purchase.signature)
311
- item.putInt("purchaseStateAndroid", purchase.purchaseState)
312
- item.putBoolean("isAcknowledgedAndroid", purchase.isAcknowledged)
313
- item.putString("packageNameAndroid", purchase.packageName)
314
- item.putString(
315
- "obfuscatedAccountIdAndroid",
316
- purchase.accountIdentifiers?.obfuscatedAccountId
317
- )
318
- item.putString(
319
- "obfuscatedProfileIdAndroid",
320
- purchase.accountIdentifiers?.obfuscatedProfileId
321
- )
322
- if (type == BillingClient.SkuType.SUBS) {
323
- item.putBoolean("autoRenewingAndroid", purchase.isAutoRenewing)
324
- }
325
- items.pushMap(item)
326
- }
327
- }
328
- promise.safeResolve(items)
329
- }
330
- }
331
- }
332
-
333
- @ReactMethod
334
- override fun getPurchaseHistoryByType(type: String, promise: Promise) {
335
- ensureConnection(
336
- promise
337
- ) { billingClient ->
338
- billingClient.queryPurchaseHistoryAsync(
339
- if (type == "subs") BillingClient.SkuType.SUBS else BillingClient.SkuType.INAPP
340
- ) { billingResult, purchaseHistoryRecordList ->
341
- if (!isValidResult(billingResult, promise)) return@queryPurchaseHistoryAsync
342
-
343
- Log.d(TAG, purchaseHistoryRecordList.toString())
344
- val items = Arguments.createArray()
345
- purchaseHistoryRecordList?.forEach { purchase ->
346
- val item = Arguments.createMap()
347
- item.putString("productId", purchase.skus[0])
348
- item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
349
- item.putString("transactionReceipt", purchase.originalJson)
350
- item.putString("purchaseToken", purchase.purchaseToken)
351
- item.putString("dataAndroid", purchase.originalJson)
352
- item.putString("signatureAndroid", purchase.signature)
353
- item.putString("developerPayload", purchase.developerPayload)
354
- items.pushMap(item)
355
- }
356
- promise.safeResolve(items)
357
- }
358
- }
359
- }
360
-
361
- @ReactMethod
362
- override fun buyItemByType(
363
- type: String,
364
- sku: String,
365
- purchaseToken: String?,
366
- prorationMode: Int,
367
- obfuscatedAccountId: String?,
368
- obfuscatedProfileId: String?,
369
- selectedOfferIndex: Int, // New optional parameter in V5 (added to maintain interface consistency)
370
- promise: Promise
371
- ) {
372
- val activity = currentActivity
373
- if (activity == null) {
374
- promise.safeReject(DoobooUtils.E_UNKNOWN, "getCurrentActivity returned null")
375
- return
376
- }
377
- ensureConnection(
378
- promise
379
- ) { billingClient ->
380
- DoobooUtils.instance.addPromiseForKey(
381
- PROMISE_BUY_ITEM,
382
- promise
383
- )
384
- val builder = BillingFlowParams.newBuilder()
385
- val selectedSku: SkuDetails? = skus[sku]
386
- if (selectedSku == null) {
387
- val debugMessage =
388
- "The sku was not found. Please fetch products first by calling getItems"
389
- val error = Arguments.createMap()
390
- error.putString("debugMessage", debugMessage)
391
- error.putString("code", PROMISE_BUY_ITEM)
392
- error.putString("message", debugMessage)
393
- error.putString("productId", sku)
394
- sendEvent(reactContext, "purchase-error", error)
395
- promise.safeReject(PROMISE_BUY_ITEM, debugMessage)
396
- return@ensureConnection
397
- }
398
- builder.setSkuDetails(selectedSku)
399
- val subscriptionUpdateParamsBuilder = SubscriptionUpdateParams.newBuilder()
400
- if (purchaseToken != null) {
401
- subscriptionUpdateParamsBuilder.setOldSkuPurchaseToken(purchaseToken)
402
- }
403
- if (obfuscatedAccountId != null) {
404
- builder.setObfuscatedAccountId(obfuscatedAccountId)
405
- }
406
- if (obfuscatedProfileId != null) {
407
- builder.setObfuscatedProfileId(obfuscatedProfileId)
408
- }
409
- if (prorationMode != null && prorationMode != -1) {
410
- if (prorationMode
411
- == BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
412
- ) {
413
- subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
414
- BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
415
- )
416
- if (type != BillingClient.SkuType.SUBS) {
417
- val debugMessage =
418
- (
419
- "IMMEDIATE_AND_CHARGE_PRORATED_PRICE for proration mode only works in" +
420
- " subscription purchase."
421
- )
422
- val error = Arguments.createMap()
423
- error.putString("debugMessage", debugMessage)
424
- error.putString("code", PROMISE_BUY_ITEM)
425
- error.putString("message", debugMessage)
426
- error.putString("productId", sku)
427
- sendEvent(reactContext, "purchase-error", error)
428
- promise.safeReject(PROMISE_BUY_ITEM, debugMessage)
429
- return@ensureConnection
430
- }
431
- } else if (prorationMode
432
- == BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
433
- ) {
434
- subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
435
- BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
436
- )
437
- } else if (prorationMode == BillingFlowParams.ProrationMode.DEFERRED) {
438
- subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
439
- BillingFlowParams.ProrationMode.DEFERRED
440
- )
441
- } else if (prorationMode
442
- == BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION
443
- ) {
444
- subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
445
- BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
446
- )
447
- } else if (prorationMode
448
- == BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
449
- ) {
450
- subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
451
- BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
452
- )
453
- } else {
454
- subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
455
- BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY
456
- )
457
- }
458
- }
459
- if (purchaseToken != null) {
460
- val subscriptionUpdateParams = subscriptionUpdateParamsBuilder.build()
461
- builder.setSubscriptionUpdateParams(subscriptionUpdateParams)
462
- }
463
- val flowParams = builder.build()
464
- val billingResultCode = billingClient.launchBillingFlow(activity, flowParams)?.responseCode ?: BillingClient.BillingResponseCode.ERROR
465
- if (billingResultCode == BillingClient.BillingResponseCode.OK) {
466
- promise.safeResolve(true)
467
- return@ensureConnection
468
- } else {
469
- val errorData: Array<String?> =
470
- PlayUtils.instance.getBillingResponseData(billingResultCode)
471
- promise.safeReject(errorData[0], errorData[1])
472
- }
473
- }
474
- }
475
-
476
- @ReactMethod
477
- override fun acknowledgePurchase(
478
- token: String,
479
- developerPayLoad: String?,
480
- promise: Promise
481
- ) {
482
- ensureConnection(
483
- promise
484
- ) { billingClient ->
485
- val acknowledgePurchaseParams =
486
- AcknowledgePurchaseParams.newBuilder().setPurchaseToken(
487
- token
488
- ).build()
489
- billingClient.acknowledgePurchase(
490
- acknowledgePurchaseParams
491
- ) { billingResult: BillingResult ->
492
- if (!isValidResult(billingResult, promise)) return@acknowledgePurchase
493
-
494
- val map = Arguments.createMap()
495
- map.putInt("responseCode", billingResult.responseCode)
496
- map.putString("debugMessage", billingResult.debugMessage)
497
- val errorData: Array<String?> = PlayUtils.instance
498
- .getBillingResponseData(billingResult.responseCode)
499
- map.putString("code", errorData[0])
500
- map.putString("message", errorData[1])
501
- promise.safeResolve(map)
502
- }
503
- }
504
- }
505
-
506
- @ReactMethod
507
- override fun consumeProduct(
508
- token: String,
509
- developerPayLoad: String?,
510
- promise: Promise
511
- ) {
512
- val params = ConsumeParams.newBuilder().setPurchaseToken(token).build()
513
- ensureConnection(
514
- promise
515
- ) { billingClient ->
516
- billingClient.consumeAsync(
517
- params
518
- ) { billingResult: BillingResult, purchaseToken: String? ->
519
- if (!isValidResult(billingResult, promise)) return@consumeAsync
520
-
521
- val map = Arguments.createMap()
522
- map.putInt("responseCode", billingResult.responseCode)
523
- map.putString("debugMessage", billingResult.debugMessage)
524
- val errorData: Array<String?> = PlayUtils.instance
525
- .getBillingResponseData(billingResult.responseCode)
526
- map.putString("code", errorData[0])
527
- map.putString("message", errorData[1])
528
- promise.safeResolve(map)
529
- }
530
- }
531
- }
532
-
533
- override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
534
- val responseCode = billingResult.responseCode
535
- if (responseCode != BillingClient.BillingResponseCode.OK) {
536
- val error = Arguments.createMap()
537
- error.putInt("responseCode", responseCode)
538
- error.putString("debugMessage", billingResult.debugMessage)
539
- val errorData: Array<String?> =
540
- PlayUtils.instance.getBillingResponseData(responseCode)
541
- error.putString("code", errorData[0])
542
- error.putString("message", errorData[1])
543
- sendEvent(reactContext, "purchase-error", error)
544
- PlayUtils.instance.rejectPromisesWithBillingError(PROMISE_BUY_ITEM, responseCode)
545
- return
546
- }
547
- if (purchases != null) {
548
- var promiseItem: WritableMap? = null
549
- for (i in purchases.indices) {
550
- val item = Arguments.createMap()
551
- val purchase = purchases[i]
552
- item.putString("productId", purchase.skus[0])
553
- item.putString("transactionId", purchase.orderId)
554
- item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
555
- item.putString("transactionReceipt", purchase.originalJson)
556
- item.putString("purchaseToken", purchase.purchaseToken)
557
- item.putString("dataAndroid", purchase.originalJson)
558
- item.putString("signatureAndroid", purchase.signature)
559
- item.putBoolean("autoRenewingAndroid", purchase.isAutoRenewing)
560
- item.putBoolean("isAcknowledgedAndroid", purchase.isAcknowledged)
561
- item.putInt("purchaseStateAndroid", purchase.purchaseState)
562
- item.putString("packageNameAndroid", purchase.packageName)
563
- item.putString("developerPayloadAndroid", purchase.developerPayload)
564
- val accountIdentifiers = purchase.accountIdentifiers
565
- if (accountIdentifiers != null) {
566
- item.putString(
567
- "obfuscatedAccountIdAndroid",
568
- accountIdentifiers.obfuscatedAccountId
569
- )
570
- item.putString(
571
- "obfuscatedProfileIdAndroid",
572
- accountIdentifiers.obfuscatedProfileId
573
- )
574
- }
575
- promiseItem = WritableNativeMap()
576
- promiseItem.merge(item)
577
- sendEvent(reactContext, "purchase-updated", item)
578
- }
579
- if (promiseItem != null) {
580
- DoobooUtils.instance.resolvePromisesForKey(PROMISE_BUY_ITEM, promiseItem)
581
- }
582
- } else {
583
- val result = Arguments.createMap()
584
- result.putInt("responseCode", billingResult.responseCode)
585
- result.putString("debugMessage", billingResult.debugMessage)
586
- result.putString(
587
- "extraMessage",
588
- "The purchases are null. This is a normal behavior if you have requested DEFERRED" +
589
- " proration. If not please report an issue."
590
- )
591
- sendEvent(reactContext, "purchase-updated", result)
592
- DoobooUtils.instance.resolvePromisesForKey(PROMISE_BUY_ITEM, null)
593
- }
594
- }
595
-
596
- private fun sendUnconsumedPurchases(promise: Promise) {
597
- ensureConnection(
598
- promise
599
- ) { billingClient ->
600
- val types = arrayOf(BillingClient.SkuType.INAPP, BillingClient.SkuType.SUBS)
601
- for (type in types) {
602
- billingClient.queryPurchasesAsync(
603
- type
604
- ) { billingResult: BillingResult, list: List<Purchase> ->
605
- if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
606
-
607
- val unacknowledgedPurchases = list.filter { !it.isAcknowledged }
608
- onPurchasesUpdated(billingResult, unacknowledgedPurchases)
609
- }
610
- }
611
- promise.safeResolve(true)
612
- }
613
- }
614
-
615
- @ReactMethod
616
- override fun startListening(promise: Promise) {
617
- sendUnconsumedPurchases(promise)
618
- }
619
-
620
- @ReactMethod
621
- override fun addListener(eventName: String) {
622
- // Keep: Required for RN built-in Event Emitter Calls.
623
- }
624
-
625
- @ReactMethod
626
- override fun removeListeners(count: Double) {
627
- // Keep: Required for RN built-in Event Emitter Calls.
628
- }
629
-
630
- @ReactMethod
631
- override fun getPackageName(promise: Promise) = promise.resolve(reactApplicationContext.packageName)
632
-
633
- private fun sendEvent(
634
- reactContext: ReactContext,
635
- eventName: String,
636
- params: WritableMap?
637
- ) {
638
- reactContext
639
- .getJSModule(RCTDeviceEventEmitter::class.java)
640
- .emit(eventName, params)
641
- }
642
-
643
- companion object {
644
- private const val PROMISE_BUY_ITEM = "PROMISE_BUY_ITEM"
645
- const val TAG = "RNIapModuleV4"
646
- }
647
-
648
- init {
649
- val lifecycleEventListener: LifecycleEventListener = object : LifecycleEventListener {
650
- override fun onHostResume() {}
651
- override fun onHostPause() {}
652
- override fun onHostDestroy() {
653
- billingClientCache?.endConnection()
654
- }
655
- }
656
- reactContext.addLifecycleEventListener(lifecycleEventListener)
657
- }
658
- }
package/babel.config.js DELETED
@@ -1,12 +0,0 @@
1
- module.exports = {
2
- presets: [
3
- 'module:metro-react-native-babel-preset',
4
- '@babel/preset-typescript',
5
- '@babel/preset-env',
6
- '@babel/preset-react',
7
- ],
8
- plugins: [
9
- '@babel/plugin-proposal-class-properties',
10
- '@babel/plugin-proposal-private-methods',
11
- ],
12
- };
package/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './src';
2
- import * as iap from './src/iap';
3
- export default iap;
package/index.js DELETED
@@ -1,3 +0,0 @@
1
- export * from './src';
2
- import * as iap from './src/iap';
3
- export default iap;
package/index.js.flow DELETED
@@ -1,9 +0,0 @@
1
- /**
2
- * Flowtype definitions for index
3
- * Generated by Flowgen from a Typescript Definition
4
- * Flowgen v1.19.0
5
- */
6
-
7
- declare export * from "./src";
8
- import * as iap from "./src/iap";
9
- declare export default typeof iap;