react-native-iap 8.6.2 → 9.0.0-beta11
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/android/build.gradle +2 -2
- package/android/src/amazon/java/com/dooboolab/RNIap/RNIapAmazonListener.kt +16 -4
- package/android/src/play/java/com/dooboolab/RNIap/RNIapModule.kt +172 -114
- package/android/src/testPlay/java/com/dooboolab/RNIap/RNIapModuleTest.kt +45 -31
- package/lib/commonjs/iap.js +17 -9
- package/lib/commonjs/iap.js.map +1 -1
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/module/iap.js +13 -8
- package/lib/module/iap.js.map +1 -1
- package/lib/module/types/index.js.map +1 -1
- package/lib/typescript/iap.d.ts +3 -1
- package/lib/typescript/types/index.d.ts +29 -5
- package/package.json +1 -1
- package/src/iap.ts +22 -9
- package/src/types/index.ts +30 -6
package/android/build.gradle
CHANGED
|
@@ -155,10 +155,10 @@ dependencies {
|
|
|
155
155
|
implementation "com.facebook.react:react-native:+"
|
|
156
156
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
|
157
157
|
|
|
158
|
-
testImplementation "junit:junit:4.13.
|
|
158
|
+
testImplementation "junit:junit:4.13.2"
|
|
159
159
|
testImplementation "io.mockk:mockk:1.12.4"
|
|
160
160
|
|
|
161
|
-
playImplementation "com.android.billingclient:billing:
|
|
161
|
+
playImplementation "com.android.billingclient:billing-ktx:5.0.0"
|
|
162
162
|
playImplementation "com.google.android.gms:play-services-base:$playServicesVersion"
|
|
163
163
|
|
|
164
164
|
amazonImplementation fileTree(dir: "libs", include: ["*.jar"])
|
|
@@ -245,7 +245,10 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
|
|
|
245
245
|
sendEvent(reactContext, "purchase-error", error)
|
|
246
246
|
DoobooUtils.instance
|
|
247
247
|
.rejectPromisesForKey(
|
|
248
|
-
RNIapAmazonModule.Companion.PROMISE_BUY_ITEM,
|
|
248
|
+
RNIapAmazonModule.Companion.PROMISE_BUY_ITEM,
|
|
249
|
+
errorCode,
|
|
250
|
+
debugMessage,
|
|
251
|
+
null
|
|
249
252
|
)
|
|
250
253
|
}
|
|
251
254
|
PurchaseResponse.RequestStatus.FAILED -> {
|
|
@@ -259,7 +262,10 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
|
|
|
259
262
|
sendEvent(reactContext, "purchase-error", error)
|
|
260
263
|
DoobooUtils.instance
|
|
261
264
|
.rejectPromisesForKey(
|
|
262
|
-
RNIapAmazonModule.Companion.PROMISE_BUY_ITEM,
|
|
265
|
+
RNIapAmazonModule.Companion.PROMISE_BUY_ITEM,
|
|
266
|
+
errorCode,
|
|
267
|
+
debugMessage,
|
|
268
|
+
null
|
|
263
269
|
)
|
|
264
270
|
}
|
|
265
271
|
PurchaseResponse.RequestStatus.INVALID_SKU -> {
|
|
@@ -272,7 +278,10 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
|
|
|
272
278
|
sendEvent(reactContext, "purchase-error", error)
|
|
273
279
|
DoobooUtils.instance
|
|
274
280
|
.rejectPromisesForKey(
|
|
275
|
-
RNIapAmazonModule.Companion.PROMISE_BUY_ITEM,
|
|
281
|
+
RNIapAmazonModule.Companion.PROMISE_BUY_ITEM,
|
|
282
|
+
errorCode,
|
|
283
|
+
debugMessage,
|
|
284
|
+
null
|
|
276
285
|
)
|
|
277
286
|
}
|
|
278
287
|
PurchaseResponse.RequestStatus.NOT_SUPPORTED -> {
|
|
@@ -285,7 +294,10 @@ class RNIapAmazonListener(private val reactContext: ReactContext) : PurchasingLi
|
|
|
285
294
|
sendEvent(reactContext, "purchase-error", error)
|
|
286
295
|
DoobooUtils.instance
|
|
287
296
|
.rejectPromisesForKey(
|
|
288
|
-
RNIapAmazonModule.Companion.PROMISE_BUY_ITEM,
|
|
297
|
+
RNIapAmazonModule.Companion.PROMISE_BUY_ITEM,
|
|
298
|
+
errorCode,
|
|
299
|
+
debugMessage,
|
|
300
|
+
null
|
|
289
301
|
)
|
|
290
302
|
}
|
|
291
303
|
}
|
|
@@ -9,10 +9,13 @@ import com.android.billingclient.api.BillingFlowParams.SubscriptionUpdateParams
|
|
|
9
9
|
import com.android.billingclient.api.BillingResult
|
|
10
10
|
import com.android.billingclient.api.ConsumeParams
|
|
11
11
|
import com.android.billingclient.api.ConsumeResponseListener
|
|
12
|
+
import com.android.billingclient.api.ProductDetails
|
|
12
13
|
import com.android.billingclient.api.Purchase
|
|
14
|
+
import com.android.billingclient.api.PurchaseHistoryRecord
|
|
13
15
|
import com.android.billingclient.api.PurchasesUpdatedListener
|
|
14
|
-
import com.android.billingclient.api.
|
|
15
|
-
import com.android.billingclient.api.
|
|
16
|
+
import com.android.billingclient.api.QueryProductDetailsParams
|
|
17
|
+
import com.android.billingclient.api.QueryPurchaseHistoryParams
|
|
18
|
+
import com.android.billingclient.api.QueryPurchasesParams
|
|
16
19
|
import com.facebook.react.bridge.Arguments
|
|
17
20
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
18
21
|
import com.facebook.react.bridge.Promise
|
|
@@ -23,13 +26,13 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
|
23
26
|
import com.facebook.react.bridge.ReactMethod
|
|
24
27
|
import com.facebook.react.bridge.ReadableArray
|
|
25
28
|
import com.facebook.react.bridge.ReadableType
|
|
29
|
+
import com.facebook.react.bridge.WritableArray
|
|
26
30
|
import com.facebook.react.bridge.WritableMap
|
|
27
31
|
import com.facebook.react.bridge.WritableNativeArray
|
|
28
32
|
import com.facebook.react.bridge.WritableNativeMap
|
|
29
33
|
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
|
|
30
34
|
import com.google.android.gms.common.ConnectionResult
|
|
31
35
|
import com.google.android.gms.common.GoogleApiAvailability
|
|
32
|
-
import java.math.BigDecimal
|
|
33
36
|
import java.util.ArrayList
|
|
34
37
|
|
|
35
38
|
class RNIapModule(
|
|
@@ -41,12 +44,12 @@ class RNIapModule(
|
|
|
41
44
|
PurchasesUpdatedListener {
|
|
42
45
|
|
|
43
46
|
private var billingClientCache: BillingClient? = null
|
|
44
|
-
private val skus: MutableMap<String,
|
|
47
|
+
private val skus: MutableMap<String, ProductDetails> = mutableMapOf()
|
|
45
48
|
override fun getName(): String {
|
|
46
49
|
return TAG
|
|
47
50
|
}
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
fun ensureConnection(
|
|
50
53
|
promise: Promise,
|
|
51
54
|
callback: (billingClient: BillingClient) -> Unit
|
|
52
55
|
) {
|
|
@@ -71,7 +74,8 @@ class RNIapModule(
|
|
|
71
74
|
{
|
|
72
75
|
if (it.size > 1 && it[0] is String && it[1] is String) {
|
|
73
76
|
promise.safeReject(
|
|
74
|
-
it[0] as String,
|
|
77
|
+
it[0] as String,
|
|
78
|
+
it[1] as String
|
|
75
79
|
)
|
|
76
80
|
} else {
|
|
77
81
|
Log.i(TAG, "Incorrect parameters in reject")
|
|
@@ -83,7 +87,7 @@ class RNIapModule(
|
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
@ReactMethod
|
|
86
|
-
|
|
90
|
+
fun initConnection(promise: Promise) {
|
|
87
91
|
if (googleApiAvailability.isGooglePlayServicesAvailable(reactContext)
|
|
88
92
|
!= ConnectionResult.SUCCESS
|
|
89
93
|
) {
|
|
@@ -104,21 +108,22 @@ class RNIapModule(
|
|
|
104
108
|
billingClientCache = it
|
|
105
109
|
it.startConnection(
|
|
106
110
|
object : BillingClientStateListener {
|
|
107
|
-
|
|
111
|
+
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
|
108
112
|
if (!isValidResult(billingResult, promise)) return
|
|
109
113
|
|
|
110
114
|
promise.safeResolve(true)
|
|
111
115
|
}
|
|
112
116
|
|
|
113
|
-
|
|
117
|
+
override fun onBillingServiceDisconnected() {
|
|
114
118
|
Log.i(TAG, "Billing service disconnected")
|
|
115
119
|
}
|
|
116
|
-
}
|
|
120
|
+
}
|
|
121
|
+
)
|
|
117
122
|
}
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
@ReactMethod
|
|
121
|
-
|
|
126
|
+
fun endConnection(promise: Promise) {
|
|
122
127
|
billingClientCache?.endConnection()
|
|
123
128
|
billingClientCache = null
|
|
124
129
|
promise.safeResolve(true)
|
|
@@ -155,12 +160,14 @@ class RNIapModule(
|
|
|
155
160
|
}
|
|
156
161
|
|
|
157
162
|
@ReactMethod
|
|
158
|
-
|
|
163
|
+
fun flushFailedPurchasesCachedAsPending(promise: Promise) {
|
|
159
164
|
ensureConnection(
|
|
160
165
|
promise
|
|
161
166
|
) { billingClient ->
|
|
162
167
|
billingClient.queryPurchasesAsync(
|
|
163
|
-
|
|
168
|
+
QueryPurchasesParams.newBuilder().setProductType(
|
|
169
|
+
BillingClient.ProductType.INAPP
|
|
170
|
+
).build()
|
|
164
171
|
) { billingResult: BillingResult, list: List<Purchase>? ->
|
|
165
172
|
if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
|
|
166
173
|
if (list == null) {
|
|
@@ -186,77 +193,96 @@ class RNIapModule(
|
|
|
186
193
|
}
|
|
187
194
|
|
|
188
195
|
@ReactMethod
|
|
189
|
-
|
|
196
|
+
fun getItemsByType(type: String, skuArr: ReadableArray, promise: Promise) {
|
|
190
197
|
ensureConnection(
|
|
191
198
|
promise
|
|
192
199
|
) { billingClient ->
|
|
193
|
-
val skuList = ArrayList<
|
|
200
|
+
val skuList = ArrayList<QueryProductDetailsParams.Product>()
|
|
194
201
|
for (i in 0 until skuArr.size()) {
|
|
195
202
|
if (skuArr.getType(i) == ReadableType.String) {
|
|
196
203
|
val sku = skuArr.getString(i)
|
|
197
|
-
|
|
204
|
+
sku?.let {
|
|
205
|
+
skuList.add(
|
|
206
|
+
QueryProductDetailsParams.Product.newBuilder().setProductId(sku)
|
|
207
|
+
.setProductType(type).build()
|
|
208
|
+
)
|
|
209
|
+
}
|
|
198
210
|
}
|
|
199
211
|
}
|
|
200
|
-
val params =
|
|
201
|
-
|
|
202
|
-
billingClient.querySkuDetailsAsync(
|
|
212
|
+
val params = QueryProductDetailsParams.newBuilder().setProductList(skuList)
|
|
213
|
+
billingClient.queryProductDetailsAsync(
|
|
203
214
|
params.build()
|
|
204
|
-
) { billingResult: BillingResult, skuDetailsList: List<
|
|
205
|
-
if (!isValidResult(billingResult, promise)) return@
|
|
215
|
+
) { billingResult: BillingResult, skuDetailsList: List<ProductDetails> ->
|
|
216
|
+
if (!isValidResult(billingResult, promise)) return@queryProductDetailsAsync
|
|
206
217
|
|
|
207
218
|
val items = Arguments.createArray()
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
val microUnitsDivisor = BigDecimal.valueOf(1000000)
|
|
223
|
-
val price = priceAmount.divide(microUnitsDivisor).toString()
|
|
224
|
-
val introductoryPriceAsAmountAndroid =
|
|
225
|
-
introductoryPriceAmount.divide(microUnitsDivisor).toString()
|
|
226
|
-
item.putString("price", price)
|
|
227
|
-
item.putString("currency", skuDetails.priceCurrencyCode)
|
|
228
|
-
item.putString("type", skuDetails.type)
|
|
229
|
-
item.putString("localizedPrice", skuDetails.price)
|
|
230
|
-
item.putString("title", skuDetails.title)
|
|
231
|
-
item.putString("description", skuDetails.description)
|
|
232
|
-
item.putString("introductoryPrice", skuDetails.introductoryPrice)
|
|
233
|
-
item.putString("typeAndroid", skuDetails.type)
|
|
234
|
-
item.putString("packageNameAndroid", skuDetails.zzc())
|
|
235
|
-
item.putString("originalPriceAndroid", skuDetails.originalPrice)
|
|
236
|
-
item.putString(
|
|
237
|
-
"subscriptionPeriodAndroid",
|
|
238
|
-
skuDetails.subscriptionPeriod
|
|
239
|
-
)
|
|
240
|
-
item.putString("freeTrialPeriodAndroid", skuDetails.freeTrialPeriod)
|
|
241
|
-
item.putString(
|
|
242
|
-
"introductoryPriceCyclesAndroid",
|
|
243
|
-
skuDetails.introductoryPriceCycles.toString()
|
|
219
|
+
for (skuDetails in skuDetailsList) {
|
|
220
|
+
skus[skuDetails.productId] = skuDetails
|
|
221
|
+
|
|
222
|
+
val item = Arguments.createMap()
|
|
223
|
+
item.putString("productId", skuDetails.productId)
|
|
224
|
+
item.putString("title", skuDetails.title)
|
|
225
|
+
item.putString("description", skuDetails.description)
|
|
226
|
+
item.putString("productType", skuDetails.productType)
|
|
227
|
+
item.putString("name", skuDetails.name)
|
|
228
|
+
val oneTimePurchaseOfferDetails = Arguments.createMap()
|
|
229
|
+
skuDetails.oneTimePurchaseOfferDetails?.let {
|
|
230
|
+
oneTimePurchaseOfferDetails.putString(
|
|
231
|
+
"priceCurrencyCode",
|
|
232
|
+
it.priceCurrencyCode
|
|
244
233
|
)
|
|
245
|
-
|
|
246
|
-
|
|
234
|
+
oneTimePurchaseOfferDetails.putString("formattedPrice", it.formattedPrice)
|
|
235
|
+
oneTimePurchaseOfferDetails.putString(
|
|
236
|
+
"priceAmountMicros",
|
|
237
|
+
it.priceAmountMicros.toString()
|
|
247
238
|
)
|
|
248
|
-
|
|
249
|
-
|
|
239
|
+
}
|
|
240
|
+
item.putMap("oneTimePurchaseOfferDetails", oneTimePurchaseOfferDetails)
|
|
241
|
+
|
|
242
|
+
val subscriptionOfferDetails = Arguments.createArray()
|
|
243
|
+
skuDetails.subscriptionOfferDetails?.forEach { subscriptionOfferDetailsItem ->
|
|
244
|
+
val offerDetails = Arguments.createMap()
|
|
245
|
+
offerDetails.putString(
|
|
246
|
+
"offerToken",
|
|
247
|
+
subscriptionOfferDetailsItem.offerToken
|
|
250
248
|
)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
249
|
+
val offerTags = Arguments.createArray()
|
|
250
|
+
subscriptionOfferDetailsItem.offerTags.forEach { offerTag ->
|
|
251
|
+
offerTags.pushString(offerTag)
|
|
252
|
+
}
|
|
253
|
+
offerDetails.putArray("offerTags", offerTags)
|
|
254
|
+
|
|
255
|
+
val pricingPhasesList = Arguments.createArray()
|
|
256
|
+
subscriptionOfferDetailsItem.pricingPhases.pricingPhaseList.forEach { pricingPhaseItem ->
|
|
257
|
+
val pricingPhase = Arguments.createMap()
|
|
258
|
+
pricingPhase.putString(
|
|
259
|
+
"formattedPrice",
|
|
260
|
+
pricingPhaseItem.formattedPrice
|
|
261
|
+
)
|
|
262
|
+
pricingPhase.putString(
|
|
263
|
+
"priceCurrencyCode",
|
|
264
|
+
pricingPhaseItem.priceCurrencyCode
|
|
265
|
+
)
|
|
266
|
+
pricingPhase.putString("billingPeriod", pricingPhaseItem.billingPeriod)
|
|
267
|
+
pricingPhase.putInt(
|
|
268
|
+
"billingCycleCount",
|
|
269
|
+
pricingPhaseItem.billingCycleCount
|
|
270
|
+
)
|
|
271
|
+
pricingPhase.putString(
|
|
272
|
+
"priceAmountMicros",
|
|
273
|
+
pricingPhaseItem.priceAmountMicros.toString()
|
|
274
|
+
)
|
|
275
|
+
pricingPhase.putInt("recurrenceMode", pricingPhaseItem.recurrenceMode)
|
|
276
|
+
|
|
277
|
+
pricingPhasesList.pushMap(pricingPhase)
|
|
278
|
+
}
|
|
279
|
+
val pricingPhases = Arguments.createMap()
|
|
280
|
+
pricingPhases.putArray("pricingPhaseList", pricingPhasesList)
|
|
281
|
+
offerDetails.putMap("pricingPhases", pricingPhases)
|
|
282
|
+
subscriptionOfferDetails.pushMap(offerDetails)
|
|
259
283
|
}
|
|
284
|
+
item.putArray("subscriptionOfferDetails", subscriptionOfferDetails)
|
|
285
|
+
items.pushMap(item)
|
|
260
286
|
}
|
|
261
287
|
promise.safeResolve(items)
|
|
262
288
|
}
|
|
@@ -286,14 +312,19 @@ class RNIapModule(
|
|
|
286
312
|
) { billingClient ->
|
|
287
313
|
val items = WritableNativeArray()
|
|
288
314
|
billingClient.queryPurchasesAsync(
|
|
289
|
-
|
|
315
|
+
QueryPurchasesParams.newBuilder().setProductType(
|
|
316
|
+
if (type == "subs") BillingClient.ProductType.SUBS else BillingClient.ProductType.INAPP
|
|
317
|
+
).build()
|
|
290
318
|
) { billingResult: BillingResult, purchases: List<Purchase>? ->
|
|
291
319
|
if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
|
|
292
320
|
if (purchases != null) {
|
|
293
321
|
for (i in purchases.indices) {
|
|
294
322
|
val purchase = purchases[i]
|
|
295
323
|
val item = WritableNativeMap()
|
|
296
|
-
item.putString("productId", purchase.
|
|
324
|
+
item.putString("productId", purchase.products[0])// kept for convenience/backward-compatibility. productIds has the complete list
|
|
325
|
+
val products = Arguments.createArray()
|
|
326
|
+
purchase.products.forEach { products.pushString(it) }
|
|
327
|
+
item.putArray("productIds", products)
|
|
297
328
|
item.putString("transactionId", purchase.orderId)
|
|
298
329
|
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
299
330
|
item.putString("transactionReceipt", purchase.originalJson)
|
|
@@ -312,7 +343,7 @@ class RNIapModule(
|
|
|
312
343
|
"obfuscatedProfileIdAndroid",
|
|
313
344
|
purchase.accountIdentifiers?.obfuscatedProfileId
|
|
314
345
|
)
|
|
315
|
-
if (type == BillingClient.
|
|
346
|
+
if (type == BillingClient.ProductType.SUBS) {
|
|
316
347
|
item.putBoolean("autoRenewingAndroid", purchase.isAutoRenewing)
|
|
317
348
|
}
|
|
318
349
|
items.pushMap(item)
|
|
@@ -329,15 +360,22 @@ class RNIapModule(
|
|
|
329
360
|
promise
|
|
330
361
|
) { billingClient ->
|
|
331
362
|
billingClient.queryPurchaseHistoryAsync(
|
|
332
|
-
|
|
333
|
-
|
|
363
|
+
QueryPurchaseHistoryParams.newBuilder().setProductType(
|
|
364
|
+
if (type == "subs") BillingClient.ProductType.SUBS else BillingClient.ProductType.INAPP
|
|
365
|
+
).build()
|
|
366
|
+
) {
|
|
367
|
+
billingResult: BillingResult, purchaseHistoryRecordList: MutableList<PurchaseHistoryRecord>? ->
|
|
368
|
+
|
|
334
369
|
if (!isValidResult(billingResult, promise)) return@queryPurchaseHistoryAsync
|
|
335
370
|
|
|
336
371
|
Log.d(TAG, purchaseHistoryRecordList.toString())
|
|
337
372
|
val items = Arguments.createArray()
|
|
338
373
|
purchaseHistoryRecordList?.forEach { purchase ->
|
|
339
374
|
val item = Arguments.createMap()
|
|
340
|
-
item.putString("productId", purchase.
|
|
375
|
+
item.putString("productId", purchase.products[0])
|
|
376
|
+
val products = Arguments.createArray()
|
|
377
|
+
purchase.products.forEach { products.pushString(it) }
|
|
378
|
+
item.putArray("productIds", products)
|
|
341
379
|
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
342
380
|
item.putString("transactionReceipt", purchase.originalJson)
|
|
343
381
|
item.putString("purchaseToken", purchase.purchaseToken)
|
|
@@ -354,11 +392,12 @@ class RNIapModule(
|
|
|
354
392
|
@ReactMethod
|
|
355
393
|
fun buyItemByType(
|
|
356
394
|
type: String,
|
|
357
|
-
|
|
395
|
+
skuArr: ReadableArray,
|
|
358
396
|
purchaseToken: String?,
|
|
359
|
-
prorationMode: Int
|
|
397
|
+
prorationMode: Int,
|
|
360
398
|
obfuscatedAccountId: String?,
|
|
361
399
|
obfuscatedProfileId: String?,
|
|
400
|
+
selectedOfferIndexArr: ReadableArray, // New optional parameter in V5
|
|
362
401
|
promise: Promise
|
|
363
402
|
) {
|
|
364
403
|
val activity = currentActivity
|
|
@@ -370,26 +409,42 @@ class RNIapModule(
|
|
|
370
409
|
promise
|
|
371
410
|
) { billingClient ->
|
|
372
411
|
DoobooUtils.instance.addPromiseForKey(
|
|
373
|
-
PROMISE_BUY_ITEM,
|
|
412
|
+
PROMISE_BUY_ITEM,
|
|
413
|
+
promise
|
|
374
414
|
)
|
|
375
|
-
val
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
415
|
+
val productParamsList =
|
|
416
|
+
skuArr.toArrayList().map { it.toString() }.mapIndexed{ index,sku ->
|
|
417
|
+
val selectedSku: ProductDetails? = skus[sku]
|
|
418
|
+
if (selectedSku == null) {
|
|
419
|
+
val debugMessage =
|
|
420
|
+
"The sku was not found. Please fetch products first by calling getItems"
|
|
421
|
+
val error = Arguments.createMap()
|
|
422
|
+
error.putString("debugMessage", debugMessage)
|
|
423
|
+
error.putString("code", PROMISE_BUY_ITEM)
|
|
424
|
+
error.putString("message", debugMessage)
|
|
425
|
+
error.putString("productId", sku)
|
|
426
|
+
sendEvent(reactContext, "purchase-error", error)
|
|
427
|
+
promise.safeReject(PROMISE_BUY_ITEM, debugMessage)
|
|
428
|
+
return@ensureConnection
|
|
429
|
+
}
|
|
430
|
+
var productParams = BillingFlowParams.ProductDetailsParams.newBuilder().setProductDetails(selectedSku)
|
|
431
|
+
val selectedOfferIndex = selectedOfferIndexArr.getInt(index)
|
|
432
|
+
if (selectedOfferIndex > -1 && (
|
|
433
|
+
selectedSku.subscriptionOfferDetails?.size
|
|
434
|
+
?: 0
|
|
435
|
+
) > selectedOfferIndex
|
|
436
|
+
) {
|
|
437
|
+
val offerToken =
|
|
438
|
+
selectedSku.subscriptionOfferDetails?.get(selectedOfferIndex)?.offerToken
|
|
439
|
+
offerToken?.let { productParams = productParams.setOfferToken(offerToken) }
|
|
440
|
+
}
|
|
441
|
+
productParams.build()
|
|
388
442
|
}
|
|
389
|
-
builder.
|
|
443
|
+
val builder = BillingFlowParams.newBuilder()
|
|
444
|
+
builder.setProductDetailsParamsList(productParamsList)
|
|
390
445
|
val subscriptionUpdateParamsBuilder = SubscriptionUpdateParams.newBuilder()
|
|
391
446
|
if (purchaseToken != null) {
|
|
392
|
-
subscriptionUpdateParamsBuilder.
|
|
447
|
+
subscriptionUpdateParamsBuilder.setOldPurchaseToken(purchaseToken)
|
|
393
448
|
}
|
|
394
449
|
if (obfuscatedAccountId != null) {
|
|
395
450
|
builder.setObfuscatedAccountId(obfuscatedAccountId)
|
|
@@ -397,14 +452,14 @@ class RNIapModule(
|
|
|
397
452
|
if (obfuscatedProfileId != null) {
|
|
398
453
|
builder.setObfuscatedProfileId(obfuscatedProfileId)
|
|
399
454
|
}
|
|
400
|
-
if (prorationMode !=
|
|
455
|
+
if (prorationMode != -1) {
|
|
401
456
|
if (prorationMode
|
|
402
457
|
== BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
403
458
|
) {
|
|
404
|
-
subscriptionUpdateParamsBuilder.
|
|
459
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
405
460
|
BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
406
461
|
)
|
|
407
|
-
if (type != BillingClient.
|
|
462
|
+
if (type != BillingClient.ProductType.SUBS) {
|
|
408
463
|
val debugMessage =
|
|
409
464
|
(
|
|
410
465
|
"IMMEDIATE_AND_CHARGE_PRORATED_PRICE for proration mode only works in" +
|
|
@@ -414,7 +469,7 @@ class RNIapModule(
|
|
|
414
469
|
error.putString("debugMessage", debugMessage)
|
|
415
470
|
error.putString("code", PROMISE_BUY_ITEM)
|
|
416
471
|
error.putString("message", debugMessage)
|
|
417
|
-
error.
|
|
472
|
+
error.putArray("productIds", skuArr)
|
|
418
473
|
sendEvent(reactContext, "purchase-error", error)
|
|
419
474
|
promise.safeReject(PROMISE_BUY_ITEM, debugMessage)
|
|
420
475
|
return@ensureConnection
|
|
@@ -422,27 +477,27 @@ class RNIapModule(
|
|
|
422
477
|
} else if (prorationMode
|
|
423
478
|
== BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
424
479
|
) {
|
|
425
|
-
subscriptionUpdateParamsBuilder.
|
|
480
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
426
481
|
BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
427
482
|
)
|
|
428
483
|
} else if (prorationMode == BillingFlowParams.ProrationMode.DEFERRED) {
|
|
429
|
-
subscriptionUpdateParamsBuilder.
|
|
484
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
430
485
|
BillingFlowParams.ProrationMode.DEFERRED
|
|
431
486
|
)
|
|
432
487
|
} else if (prorationMode
|
|
433
488
|
== BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION
|
|
434
489
|
) {
|
|
435
|
-
subscriptionUpdateParamsBuilder.
|
|
490
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
436
491
|
BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
437
492
|
)
|
|
438
493
|
} else if (prorationMode
|
|
439
494
|
== BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
|
|
440
495
|
) {
|
|
441
|
-
subscriptionUpdateParamsBuilder.
|
|
496
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
442
497
|
BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
|
|
443
498
|
)
|
|
444
499
|
} else {
|
|
445
|
-
subscriptionUpdateParamsBuilder.
|
|
500
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
446
501
|
BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY
|
|
447
502
|
)
|
|
448
503
|
}
|
|
@@ -452,7 +507,7 @@ class RNIapModule(
|
|
|
452
507
|
builder.setSubscriptionUpdateParams(subscriptionUpdateParams)
|
|
453
508
|
}
|
|
454
509
|
val flowParams = builder.build()
|
|
455
|
-
val billingResultCode = billingClient.launchBillingFlow(activity, flowParams)
|
|
510
|
+
val billingResultCode = billingClient.launchBillingFlow(activity, flowParams).responseCode
|
|
456
511
|
if (billingResultCode == BillingClient.BillingResponseCode.OK) {
|
|
457
512
|
promise.safeResolve(true)
|
|
458
513
|
return@ensureConnection
|
|
@@ -516,6 +571,7 @@ class RNIapModule(
|
|
|
516
571
|
.getBillingResponseData(billingResult.responseCode)
|
|
517
572
|
map.putString("code", errorData[0])
|
|
518
573
|
map.putString("message", errorData[1])
|
|
574
|
+
map.putString("purchaseToken",purchaseToken)
|
|
519
575
|
promise.safeResolve(map)
|
|
520
576
|
}
|
|
521
577
|
}
|
|
@@ -536,11 +592,13 @@ class RNIapModule(
|
|
|
536
592
|
return
|
|
537
593
|
}
|
|
538
594
|
if (purchases != null) {
|
|
539
|
-
|
|
540
|
-
|
|
595
|
+
val promiseItems: WritableArray = Arguments.createArray()
|
|
596
|
+
purchases.forEach { purchase ->
|
|
541
597
|
val item = Arguments.createMap()
|
|
542
|
-
|
|
543
|
-
|
|
598
|
+
item.putString("productId", purchase.products[0])
|
|
599
|
+
val products = Arguments.createArray()
|
|
600
|
+
purchase.products.forEach { products.pushString(it) }
|
|
601
|
+
item.putArray("productIds", products)
|
|
544
602
|
item.putString("transactionId", purchase.orderId)
|
|
545
603
|
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
546
604
|
item.putString("transactionReceipt", purchase.originalJson)
|
|
@@ -563,13 +621,10 @@ class RNIapModule(
|
|
|
563
621
|
accountIdentifiers.obfuscatedProfileId
|
|
564
622
|
)
|
|
565
623
|
}
|
|
566
|
-
|
|
567
|
-
promiseItem.merge(item)
|
|
624
|
+
promiseItems.pushMap(item)
|
|
568
625
|
sendEvent(reactContext, "purchase-updated", item)
|
|
569
626
|
}
|
|
570
|
-
|
|
571
|
-
DoobooUtils.instance.resolvePromisesForKey(PROMISE_BUY_ITEM, promiseItem)
|
|
572
|
-
}
|
|
627
|
+
DoobooUtils.instance.resolvePromisesForKey(PROMISE_BUY_ITEM, promiseItems)
|
|
573
628
|
} else {
|
|
574
629
|
val result = Arguments.createMap()
|
|
575
630
|
result.putInt("responseCode", billingResult.responseCode)
|
|
@@ -588,10 +643,12 @@ class RNIapModule(
|
|
|
588
643
|
ensureConnection(
|
|
589
644
|
promise
|
|
590
645
|
) { billingClient ->
|
|
591
|
-
val types = arrayOf(BillingClient.
|
|
646
|
+
val types = arrayOf(BillingClient.ProductType.INAPP, BillingClient.ProductType.SUBS)
|
|
592
647
|
for (type in types) {
|
|
593
648
|
billingClient.queryPurchasesAsync(
|
|
594
|
-
|
|
649
|
+
QueryPurchasesParams.newBuilder().setProductType(
|
|
650
|
+
type
|
|
651
|
+
).build()
|
|
595
652
|
) { billingResult: BillingResult, list: List<Purchase> ->
|
|
596
653
|
if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
|
|
597
654
|
|
|
@@ -642,6 +699,7 @@ class RNIapModule(
|
|
|
642
699
|
override fun onHostPause() {}
|
|
643
700
|
override fun onHostDestroy() {
|
|
644
701
|
billingClientCache?.endConnection()
|
|
702
|
+
billingClientCache = null
|
|
645
703
|
}
|
|
646
704
|
}
|
|
647
705
|
reactContext.addLifecycleEventListener(lifecycleEventListener)
|