react-native-iap 8.4.0 → 9.0.0-beta
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/.yarn/install-state.gz +0 -0
- package/android/build.gradle +3 -3
- package/android/src/amazon/java/com/dooboolab/RNIap/RNIapAmazonListener.kt +16 -4
- package/android/src/play/java/com/dooboolab/RNIap/RNIapModule.kt +142 -97
- package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleInterface.kt +44 -0
- package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleV4.kt +656 -0
- package/android/src/play/java/com/dooboolab/RNIap/RNIapPackage.kt +1 -0
- package/android/src/testPlay/java/com/dooboolab/RNIap/{RNIapModuleTest.kt → RNIapModuleTestV4.kt} +5 -5
- package/package.json +1 -1
- package/src/iap.d.ts +1 -1
- package/src/iap.js +24 -10
- package/src/types/index.d.ts +22 -0
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
package/android/build.gradle
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
buildscript {
|
|
2
|
-
ext.DEFAULT_KOTLIN_VERSION = '1.
|
|
2
|
+
ext.DEFAULT_KOTLIN_VERSION = '1.7.10'
|
|
3
3
|
ext.safeExtGet={prop, fallback->
|
|
4
4
|
return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
5
5
|
}
|
|
@@ -23,7 +23,7 @@ def DEFAULT_COMPILE_SDK_VERSION = 30
|
|
|
23
23
|
def DEFAULT_BUILD_TOOLS_VERSION = "30.0.2"
|
|
24
24
|
def DEFAULT_MIN_SDK_VERSION = 16
|
|
25
25
|
def DEFAULT_TARGET_SDK_VERSION = 30
|
|
26
|
-
def DEFAULT_PLAY_SERVICES_VERSION = "
|
|
26
|
+
def DEFAULT_PLAY_SERVICES_VERSION = "18.1.0"
|
|
27
27
|
|
|
28
28
|
android {
|
|
29
29
|
compileSdkVersion safeExtGet("compileSdkVersion", DEFAULT_COMPILE_SDK_VERSION)
|
|
@@ -68,7 +68,7 @@ dependencies {
|
|
|
68
68
|
implementation 'com.facebook.react:react-native:+'
|
|
69
69
|
testImplementation 'junit:junit:4.13.1'
|
|
70
70
|
testImplementation "io.mockk:mockk:1.12.4"
|
|
71
|
-
playImplementation 'com.android.billingclient:billing:
|
|
71
|
+
playImplementation 'com.android.billingclient:billing:5.0.0'
|
|
72
72
|
def playServicesVersion = safeExtGet('playServicesVersion', DEFAULT_PLAY_SERVICES_VERSION)
|
|
73
73
|
playImplementation "com.google.android.gms:play-services-base:$playServicesVersion"
|
|
74
74
|
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
|
|
@@ -29,7 +32,6 @@ import com.facebook.react.bridge.WritableNativeMap
|
|
|
29
32
|
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
|
|
30
33
|
import com.google.android.gms.common.ConnectionResult
|
|
31
34
|
import com.google.android.gms.common.GoogleApiAvailability
|
|
32
|
-
import java.math.BigDecimal
|
|
33
35
|
import java.util.ArrayList
|
|
34
36
|
|
|
35
37
|
class RNIapModule(
|
|
@@ -38,10 +40,11 @@ class RNIapModule(
|
|
|
38
40
|
private val googleApiAvailability: GoogleApiAvailability = GoogleApiAvailability.getInstance()
|
|
39
41
|
) :
|
|
40
42
|
ReactContextBaseJavaModule(reactContext),
|
|
41
|
-
PurchasesUpdatedListener
|
|
43
|
+
PurchasesUpdatedListener,
|
|
44
|
+
RNIapModuleInterface {
|
|
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
|
}
|
|
@@ -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
|
-
fun initConnection(promise: Promise) {
|
|
90
|
+
override fun initConnection(promise: Promise) {
|
|
87
91
|
if (googleApiAvailability.isGooglePlayServicesAvailable(reactContext)
|
|
88
92
|
!= ConnectionResult.SUCCESS
|
|
89
93
|
) {
|
|
@@ -113,12 +117,13 @@ class RNIapModule(
|
|
|
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
|
-
fun endConnection(promise: Promise) {
|
|
126
|
+
override 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
|
-
fun flushFailedPurchasesCachedAsPending(promise: Promise) {
|
|
163
|
+
override 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,94 @@ class RNIapModule(
|
|
|
186
193
|
}
|
|
187
194
|
|
|
188
195
|
@ReactMethod
|
|
189
|
-
fun getItemsByType(type: String, skuArr: ReadableArray, promise: Promise) {
|
|
196
|
+
override 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
|
-
skuList.add(
|
|
204
|
+
skuList.add(
|
|
205
|
+
QueryProductDetailsParams.Product.newBuilder().setProductId(sku)
|
|
206
|
+
.setProductType(type).build()
|
|
207
|
+
)
|
|
198
208
|
}
|
|
199
209
|
}
|
|
200
|
-
val params =
|
|
201
|
-
|
|
202
|
-
billingClient.querySkuDetailsAsync(
|
|
210
|
+
val params = QueryProductDetailsParams.newBuilder().setProductList(skuList)
|
|
211
|
+
billingClient.queryProductDetailsAsync(
|
|
203
212
|
params.build()
|
|
204
|
-
) { billingResult: BillingResult, skuDetailsList: List<
|
|
205
|
-
if (!isValidResult(billingResult, promise)) return@
|
|
213
|
+
) { billingResult: BillingResult, skuDetailsList: List<ProductDetails> ->
|
|
214
|
+
if (!isValidResult(billingResult, promise)) return@queryProductDetailsAsync
|
|
206
215
|
|
|
207
216
|
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()
|
|
217
|
+
for (skuDetails in skuDetailsList) {
|
|
218
|
+
skus[skuDetails.productId] = skuDetails
|
|
219
|
+
|
|
220
|
+
val item = Arguments.createMap()
|
|
221
|
+
item.putString("productId", skuDetails.productId)
|
|
222
|
+
item.putString("title", skuDetails.title)
|
|
223
|
+
item.putString("description", skuDetails.description)
|
|
224
|
+
item.putString("productType", skuDetails.productType)
|
|
225
|
+
item.putString("name", skuDetails.name)
|
|
226
|
+
val oneTimePurchaseOfferDetails = Arguments.createMap()
|
|
227
|
+
skuDetails.oneTimePurchaseOfferDetails?.let {
|
|
228
|
+
oneTimePurchaseOfferDetails.putString(
|
|
229
|
+
"priceCurrencyCode",
|
|
230
|
+
it.priceCurrencyCode
|
|
244
231
|
)
|
|
245
|
-
|
|
246
|
-
|
|
232
|
+
oneTimePurchaseOfferDetails.putString("formattedPrice", it.formattedPrice)
|
|
233
|
+
oneTimePurchaseOfferDetails.putString(
|
|
234
|
+
"priceAmountMicros",
|
|
235
|
+
it.priceAmountMicros.toString()
|
|
247
236
|
)
|
|
248
|
-
|
|
249
|
-
|
|
237
|
+
}
|
|
238
|
+
item.putMap("oneTimePurchaseOfferDetails", oneTimePurchaseOfferDetails)
|
|
239
|
+
|
|
240
|
+
val subscriptionOfferDetails = Arguments.createArray()
|
|
241
|
+
skuDetails.subscriptionOfferDetails?.forEach { subscriptionOfferDetailsItem ->
|
|
242
|
+
val offerDetails = Arguments.createMap()
|
|
243
|
+
offerDetails.putString(
|
|
244
|
+
"offerToken",
|
|
245
|
+
subscriptionOfferDetailsItem.offerToken
|
|
250
246
|
)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
247
|
+
val offerTags = Arguments.createArray()
|
|
248
|
+
subscriptionOfferDetailsItem.offerTags.forEach { offerTag ->
|
|
249
|
+
offerTags.pushString(offerTag)
|
|
250
|
+
}
|
|
251
|
+
offerDetails.putArray("offerTags", offerTags)
|
|
252
|
+
|
|
253
|
+
val pricingPhasesList = Arguments.createArray()
|
|
254
|
+
subscriptionOfferDetailsItem.pricingPhases.pricingPhaseList.forEach { pricingPhaseItem ->
|
|
255
|
+
val pricingPhase = Arguments.createMap()
|
|
256
|
+
pricingPhase.putString(
|
|
257
|
+
"formattedPrice",
|
|
258
|
+
pricingPhaseItem.formattedPrice
|
|
259
|
+
)
|
|
260
|
+
pricingPhase.putString(
|
|
261
|
+
"priceCurrencyCode",
|
|
262
|
+
pricingPhaseItem.priceCurrencyCode
|
|
263
|
+
)
|
|
264
|
+
pricingPhase.putString("billingPeriod", pricingPhaseItem.billingPeriod)
|
|
265
|
+
pricingPhase.putInt(
|
|
266
|
+
"billingCycleCount",
|
|
267
|
+
pricingPhaseItem.billingCycleCount
|
|
268
|
+
)
|
|
269
|
+
pricingPhase.putString(
|
|
270
|
+
"priceAmountMicros",
|
|
271
|
+
pricingPhaseItem.priceAmountMicros.toString()
|
|
272
|
+
)
|
|
273
|
+
pricingPhase.putInt("recurrenceMode", pricingPhaseItem.recurrenceMode)
|
|
274
|
+
|
|
275
|
+
pricingPhasesList.pushMap(pricingPhase)
|
|
276
|
+
}
|
|
277
|
+
val pricingPhases = Arguments.createMap()
|
|
278
|
+
pricingPhases.putArray("pricingPhaseList", pricingPhasesList)
|
|
279
|
+
offerDetails.putMap("pricingPhases", pricingPhases)
|
|
280
|
+
subscriptionOfferDetails.pushMap(offerDetails)
|
|
259
281
|
}
|
|
282
|
+
item.putArray("subscriptionOfferDetails", subscriptionOfferDetails)
|
|
283
|
+
items.pushMap(item)
|
|
260
284
|
}
|
|
261
285
|
promise.safeResolve(items)
|
|
262
286
|
}
|
|
@@ -280,20 +304,22 @@ class RNIapModule(
|
|
|
280
304
|
}
|
|
281
305
|
|
|
282
306
|
@ReactMethod
|
|
283
|
-
fun getAvailableItemsByType(type: String, promise: Promise) {
|
|
307
|
+
override fun getAvailableItemsByType(type: String, promise: Promise) {
|
|
284
308
|
ensureConnection(
|
|
285
309
|
promise
|
|
286
310
|
) { billingClient ->
|
|
287
311
|
val items = WritableNativeArray()
|
|
288
312
|
billingClient.queryPurchasesAsync(
|
|
289
|
-
|
|
313
|
+
QueryPurchasesParams.newBuilder().setProductType(
|
|
314
|
+
if (type == "subs") BillingClient.ProductType.SUBS else BillingClient.ProductType.INAPP
|
|
315
|
+
).build()
|
|
290
316
|
) { billingResult: BillingResult, purchases: List<Purchase>? ->
|
|
291
317
|
if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
|
|
292
318
|
if (purchases != null) {
|
|
293
319
|
for (i in purchases.indices) {
|
|
294
320
|
val purchase = purchases[i]
|
|
295
321
|
val item = WritableNativeMap()
|
|
296
|
-
item.putString("productId", purchase.
|
|
322
|
+
item.putString("productId", purchase.products[0]) // TODO: should be a list
|
|
297
323
|
item.putString("transactionId", purchase.orderId)
|
|
298
324
|
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
299
325
|
item.putString("transactionReceipt", purchase.originalJson)
|
|
@@ -312,7 +338,7 @@ class RNIapModule(
|
|
|
312
338
|
"obfuscatedProfileIdAndroid",
|
|
313
339
|
purchase.accountIdentifiers?.obfuscatedProfileId
|
|
314
340
|
)
|
|
315
|
-
if (type == BillingClient.
|
|
341
|
+
if (type == BillingClient.ProductType.SUBS) {
|
|
316
342
|
item.putBoolean("autoRenewingAndroid", purchase.isAutoRenewing)
|
|
317
343
|
}
|
|
318
344
|
items.pushMap(item)
|
|
@@ -324,20 +350,24 @@ class RNIapModule(
|
|
|
324
350
|
}
|
|
325
351
|
|
|
326
352
|
@ReactMethod
|
|
327
|
-
fun getPurchaseHistoryByType(type: String, promise: Promise) {
|
|
353
|
+
override fun getPurchaseHistoryByType(type: String, promise: Promise) {
|
|
328
354
|
ensureConnection(
|
|
329
355
|
promise
|
|
330
356
|
) { billingClient ->
|
|
331
357
|
billingClient.queryPurchaseHistoryAsync(
|
|
332
|
-
|
|
333
|
-
|
|
358
|
+
QueryPurchaseHistoryParams.newBuilder().setProductType(
|
|
359
|
+
if (type == "subs") BillingClient.ProductType.SUBS else BillingClient.ProductType.INAPP
|
|
360
|
+
).build()
|
|
361
|
+
) {
|
|
362
|
+
billingResult: BillingResult, purchaseHistoryRecordList: MutableList<PurchaseHistoryRecord>? ->
|
|
363
|
+
|
|
334
364
|
if (!isValidResult(billingResult, promise)) return@queryPurchaseHistoryAsync
|
|
335
365
|
|
|
336
366
|
Log.d(TAG, purchaseHistoryRecordList.toString())
|
|
337
367
|
val items = Arguments.createArray()
|
|
338
368
|
purchaseHistoryRecordList?.forEach { purchase ->
|
|
339
369
|
val item = Arguments.createMap()
|
|
340
|
-
item.putString("productId", purchase.
|
|
370
|
+
item.putString("productId", purchase.products[0])
|
|
341
371
|
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
342
372
|
item.putString("transactionReceipt", purchase.originalJson)
|
|
343
373
|
item.putString("purchaseToken", purchase.purchaseToken)
|
|
@@ -352,13 +382,14 @@ class RNIapModule(
|
|
|
352
382
|
}
|
|
353
383
|
|
|
354
384
|
@ReactMethod
|
|
355
|
-
fun buyItemByType(
|
|
385
|
+
override fun buyItemByType(
|
|
356
386
|
type: String,
|
|
357
|
-
sku: String,
|
|
387
|
+
sku: String, // TODO: should this now be an array?
|
|
358
388
|
purchaseToken: String?,
|
|
359
389
|
prorationMode: Int?,
|
|
360
390
|
obfuscatedAccountId: String?,
|
|
361
391
|
obfuscatedProfileId: String?,
|
|
392
|
+
selectedOfferIndex: Int?, // New optional parameter in V5, TODO: should it be an array?
|
|
362
393
|
promise: Promise
|
|
363
394
|
) {
|
|
364
395
|
val activity = currentActivity
|
|
@@ -370,10 +401,11 @@ class RNIapModule(
|
|
|
370
401
|
promise
|
|
371
402
|
) { billingClient ->
|
|
372
403
|
DoobooUtils.instance.addPromiseForKey(
|
|
373
|
-
PROMISE_BUY_ITEM,
|
|
404
|
+
PROMISE_BUY_ITEM,
|
|
405
|
+
promise
|
|
374
406
|
)
|
|
375
407
|
val builder = BillingFlowParams.newBuilder()
|
|
376
|
-
val selectedSku:
|
|
408
|
+
val selectedSku: ProductDetails? = skus[sku]
|
|
377
409
|
if (selectedSku == null) {
|
|
378
410
|
val debugMessage =
|
|
379
411
|
"The sku was not found. Please fetch products first by calling getItems"
|
|
@@ -386,10 +418,21 @@ class RNIapModule(
|
|
|
386
418
|
promise.safeReject(PROMISE_BUY_ITEM, debugMessage)
|
|
387
419
|
return@ensureConnection
|
|
388
420
|
}
|
|
389
|
-
|
|
421
|
+
var productParams = BillingFlowParams.ProductDetailsParams.newBuilder().setProductDetails(selectedSku)
|
|
422
|
+
if (selectedOfferIndex != null && (
|
|
423
|
+
selectedSku.subscriptionOfferDetails?.size
|
|
424
|
+
?: 0
|
|
425
|
+
) > selectedOfferIndex
|
|
426
|
+
) {
|
|
427
|
+
val offerToken =
|
|
428
|
+
selectedSku.subscriptionOfferDetails?.get(selectedOfferIndex)?.offerToken
|
|
429
|
+
offerToken?.let { productParams = productParams.setOfferToken(offerToken) }
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
builder.setProductDetailsParamsList(listOf(productParams.build()))
|
|
390
433
|
val subscriptionUpdateParamsBuilder = SubscriptionUpdateParams.newBuilder()
|
|
391
434
|
if (purchaseToken != null) {
|
|
392
|
-
subscriptionUpdateParamsBuilder.
|
|
435
|
+
subscriptionUpdateParamsBuilder.setOldPurchaseToken(purchaseToken)
|
|
393
436
|
}
|
|
394
437
|
if (obfuscatedAccountId != null) {
|
|
395
438
|
builder.setObfuscatedAccountId(obfuscatedAccountId)
|
|
@@ -401,7 +444,7 @@ class RNIapModule(
|
|
|
401
444
|
if (prorationMode
|
|
402
445
|
== BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
403
446
|
) {
|
|
404
|
-
subscriptionUpdateParamsBuilder.
|
|
447
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
405
448
|
BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
406
449
|
)
|
|
407
450
|
if (type != BillingClient.SkuType.SUBS) {
|
|
@@ -422,27 +465,27 @@ class RNIapModule(
|
|
|
422
465
|
} else if (prorationMode
|
|
423
466
|
== BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
424
467
|
) {
|
|
425
|
-
subscriptionUpdateParamsBuilder.
|
|
468
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
426
469
|
BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
427
470
|
)
|
|
428
471
|
} else if (prorationMode == BillingFlowParams.ProrationMode.DEFERRED) {
|
|
429
|
-
subscriptionUpdateParamsBuilder.
|
|
472
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
430
473
|
BillingFlowParams.ProrationMode.DEFERRED
|
|
431
474
|
)
|
|
432
475
|
} else if (prorationMode
|
|
433
476
|
== BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION
|
|
434
477
|
) {
|
|
435
|
-
subscriptionUpdateParamsBuilder.
|
|
478
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
436
479
|
BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
437
480
|
)
|
|
438
481
|
} else if (prorationMode
|
|
439
482
|
== BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
|
|
440
483
|
) {
|
|
441
|
-
subscriptionUpdateParamsBuilder.
|
|
484
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
442
485
|
BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
|
|
443
486
|
)
|
|
444
487
|
} else {
|
|
445
|
-
subscriptionUpdateParamsBuilder.
|
|
488
|
+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(
|
|
446
489
|
BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY
|
|
447
490
|
)
|
|
448
491
|
}
|
|
@@ -452,7 +495,7 @@ class RNIapModule(
|
|
|
452
495
|
builder.setSubscriptionUpdateParams(subscriptionUpdateParams)
|
|
453
496
|
}
|
|
454
497
|
val flowParams = builder.build()
|
|
455
|
-
val billingResultCode = billingClient.launchBillingFlow(activity, flowParams)
|
|
498
|
+
val billingResultCode = billingClient.launchBillingFlow(activity, flowParams).responseCode
|
|
456
499
|
if (billingResultCode == BillingClient.BillingResponseCode.OK) {
|
|
457
500
|
promise.safeResolve(true)
|
|
458
501
|
return@ensureConnection
|
|
@@ -465,7 +508,7 @@ class RNIapModule(
|
|
|
465
508
|
}
|
|
466
509
|
|
|
467
510
|
@ReactMethod
|
|
468
|
-
fun acknowledgePurchase(
|
|
511
|
+
override fun acknowledgePurchase(
|
|
469
512
|
token: String,
|
|
470
513
|
developerPayLoad: String?,
|
|
471
514
|
promise: Promise
|
|
@@ -495,7 +538,7 @@ class RNIapModule(
|
|
|
495
538
|
}
|
|
496
539
|
|
|
497
540
|
@ReactMethod
|
|
498
|
-
fun consumeProduct(
|
|
541
|
+
override fun consumeProduct(
|
|
499
542
|
token: String,
|
|
500
543
|
developerPayLoad: String?,
|
|
501
544
|
promise: Promise
|
|
@@ -540,7 +583,7 @@ class RNIapModule(
|
|
|
540
583
|
for (i in purchases.indices) {
|
|
541
584
|
val item = Arguments.createMap()
|
|
542
585
|
val purchase = purchases[i]
|
|
543
|
-
item.putString("productId", purchase.
|
|
586
|
+
item.putString("productId", purchase.products[0])
|
|
544
587
|
item.putString("transactionId", purchase.orderId)
|
|
545
588
|
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
546
589
|
item.putString("transactionReceipt", purchase.originalJson)
|
|
@@ -588,10 +631,12 @@ class RNIapModule(
|
|
|
588
631
|
ensureConnection(
|
|
589
632
|
promise
|
|
590
633
|
) { billingClient ->
|
|
591
|
-
val types = arrayOf(BillingClient.
|
|
634
|
+
val types = arrayOf(BillingClient.ProductType.INAPP, BillingClient.ProductType.SUBS)
|
|
592
635
|
for (type in types) {
|
|
593
636
|
billingClient.queryPurchasesAsync(
|
|
594
|
-
|
|
637
|
+
QueryPurchasesParams.newBuilder().setProductType(
|
|
638
|
+
type
|
|
639
|
+
).build()
|
|
595
640
|
) { billingResult: BillingResult, list: List<Purchase> ->
|
|
596
641
|
if (!isValidResult(billingResult, promise)) return@queryPurchasesAsync
|
|
597
642
|
|
|
@@ -604,22 +649,22 @@ class RNIapModule(
|
|
|
604
649
|
}
|
|
605
650
|
|
|
606
651
|
@ReactMethod
|
|
607
|
-
fun startListening(promise: Promise) {
|
|
652
|
+
override fun startListening(promise: Promise) {
|
|
608
653
|
sendUnconsumedPurchases(promise)
|
|
609
654
|
}
|
|
610
655
|
|
|
611
656
|
@ReactMethod
|
|
612
|
-
fun addListener(eventName: String) {
|
|
657
|
+
override fun addListener(eventName: String) {
|
|
613
658
|
// Keep: Required for RN built-in Event Emitter Calls.
|
|
614
659
|
}
|
|
615
660
|
|
|
616
661
|
@ReactMethod
|
|
617
|
-
fun removeListeners(count: Double) {
|
|
662
|
+
override fun removeListeners(count: Double) {
|
|
618
663
|
// Keep: Required for RN built-in Event Emitter Calls.
|
|
619
664
|
}
|
|
620
665
|
|
|
621
666
|
@ReactMethod
|
|
622
|
-
fun getPackageName(promise: Promise) = promise.resolve(reactApplicationContext.packageName)
|
|
667
|
+
override fun getPackageName(promise: Promise) = promise.resolve(reactApplicationContext.packageName)
|
|
623
668
|
|
|
624
669
|
private fun sendEvent(
|
|
625
670
|
reactContext: ReactContext,
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package com.dooboolab.RNIap
|
|
2
|
+
|
|
3
|
+
import com.android.billingclient.api.BillingResult
|
|
4
|
+
import com.android.billingclient.api.Purchase
|
|
5
|
+
import com.facebook.react.bridge.Promise
|
|
6
|
+
import com.facebook.react.bridge.ReadableArray
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Common interface for consistency
|
|
10
|
+
*/
|
|
11
|
+
interface RNIapModuleInterface {
|
|
12
|
+
fun getName(): String
|
|
13
|
+
fun initConnection(promise: Promise)
|
|
14
|
+
fun endConnection(promise: Promise)
|
|
15
|
+
fun flushFailedPurchasesCachedAsPending(promise: Promise)
|
|
16
|
+
fun getItemsByType(type: String, skuArr: ReadableArray, promise: Promise)
|
|
17
|
+
fun getAvailableItemsByType(type: String, promise: Promise)
|
|
18
|
+
fun getPurchaseHistoryByType(type: String, promise: Promise)
|
|
19
|
+
fun buyItemByType(
|
|
20
|
+
type: String,
|
|
21
|
+
sku: String,
|
|
22
|
+
purchaseToken: String?,
|
|
23
|
+
prorationMode: Int?,
|
|
24
|
+
obfuscatedAccountId: String?,
|
|
25
|
+
obfuscatedProfileId: String?,
|
|
26
|
+
selectedOfferIndex: Int?, // New optional parameter in V5 (added to maintain interface consistency)
|
|
27
|
+
promise: Promise
|
|
28
|
+
)
|
|
29
|
+
fun acknowledgePurchase(
|
|
30
|
+
token: String,
|
|
31
|
+
developerPayLoad: String?,
|
|
32
|
+
promise: Promise
|
|
33
|
+
)
|
|
34
|
+
fun consumeProduct(
|
|
35
|
+
token: String,
|
|
36
|
+
developerPayLoad: String?,
|
|
37
|
+
promise: Promise
|
|
38
|
+
)
|
|
39
|
+
fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?)
|
|
40
|
+
fun startListening(promise: Promise)
|
|
41
|
+
fun addListener(eventName: String)
|
|
42
|
+
fun removeListeners(count: Double)
|
|
43
|
+
fun getPackageName(promise: Promise)
|
|
44
|
+
}
|