react-native-iap 8.1.2 → 8.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
|
@@ -17,6 +17,7 @@ import com.facebook.react.bridge.Arguments
|
|
|
17
17
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
18
18
|
import com.facebook.react.bridge.ObjectAlreadyConsumedException
|
|
19
19
|
import com.facebook.react.bridge.Promise
|
|
20
|
+
import com.facebook.react.bridge.PromiseImpl
|
|
20
21
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
21
22
|
import com.facebook.react.bridge.ReactContext
|
|
22
23
|
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
@@ -28,37 +29,50 @@ import com.facebook.react.bridge.WritableNativeMap
|
|
|
28
29
|
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
|
|
29
30
|
import com.google.android.gms.common.ConnectionResult
|
|
30
31
|
import com.google.android.gms.common.GoogleApiAvailability
|
|
31
|
-
import java.lang.Exception
|
|
32
32
|
import java.math.BigDecimal
|
|
33
33
|
import java.util.ArrayList
|
|
34
34
|
|
|
35
|
-
class RNIapModule(reactContext: ReactApplicationContext) :
|
|
35
|
+
class RNIapModule(private val reactContext: ReactApplicationContext) :
|
|
36
36
|
ReactContextBaseJavaModule(reactContext),
|
|
37
37
|
PurchasesUpdatedListener {
|
|
38
|
-
|
|
39
|
-
private val
|
|
40
|
-
|
|
41
|
-
private val skus: MutableMap<String, SkuDetails>
|
|
38
|
+
|
|
39
|
+
private val billingClient: BillingClient = BillingClient.newBuilder(reactContext).enablePendingPurchases().setListener(this)
|
|
40
|
+
.build()
|
|
41
|
+
private val skus: MutableMap<String, SkuDetails> = mutableMapOf()
|
|
42
42
|
override fun getName(): String {
|
|
43
43
|
return "RNIapModule"
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
private
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
private fun ensureConnection(promise: Promise, callback: EnsureConnectionCallback) {
|
|
51
|
-
val billingClient = billingClientCache
|
|
52
|
-
if (billingClient?.isReady == true) {
|
|
53
|
-
callback.run(billingClient)
|
|
46
|
+
private fun ensureConnection(promise: Promise, callback: () -> Unit) {
|
|
47
|
+
if (billingClient.isReady) {
|
|
48
|
+
callback()
|
|
54
49
|
return
|
|
50
|
+
} else {
|
|
51
|
+
val nested = PromiseImpl(
|
|
52
|
+
{
|
|
53
|
+
if (it.isNotEmpty() && it[0] is Boolean && it[0] as Boolean) {
|
|
54
|
+
callback()
|
|
55
|
+
} else {
|
|
56
|
+
Log.i(TAG, "Incorrect parameter in resolve")
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
if (it.size > 1 && it[0] is String && it[1] is String) {
|
|
61
|
+
promise.reject(
|
|
62
|
+
it[0] as String, it[1] as String
|
|
63
|
+
)
|
|
64
|
+
} else {
|
|
65
|
+
Log.i(TAG, "Incorrect parameters in reject")
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
initConnection(nested)
|
|
55
70
|
}
|
|
56
|
-
promise.reject(DoobooUtils.E_NOT_PREPARED, "Not initialized, Please call initConnection()")
|
|
57
71
|
}
|
|
58
72
|
|
|
59
73
|
@ReactMethod
|
|
60
74
|
fun initConnection(promise: Promise) {
|
|
61
|
-
if (
|
|
75
|
+
if (billingClient.isReady) {
|
|
62
76
|
Log.i(
|
|
63
77
|
TAG,
|
|
64
78
|
"Already initialized, you should only call initConnection() once when your app starts"
|
|
@@ -70,13 +84,11 @@ class RNIapModule(reactContext: ReactApplicationContext) :
|
|
|
70
84
|
!= ConnectionResult.SUCCESS
|
|
71
85
|
) {
|
|
72
86
|
Log.i(TAG, "Google Play Services are not available on this device")
|
|
73
|
-
promise.
|
|
87
|
+
promise.reject(DoobooUtils.E_NOT_PREPARED, "Google Play Services are not available on this device")
|
|
74
88
|
return
|
|
75
89
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.build()
|
|
79
|
-
billingClientCache!!.startConnection(
|
|
90
|
+
|
|
91
|
+
billingClient.startConnection(
|
|
80
92
|
object : BillingClientStateListener {
|
|
81
93
|
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
|
82
94
|
val responseCode = billingResult.responseCode
|
|
@@ -93,32 +105,15 @@ class RNIapModule(reactContext: ReactApplicationContext) :
|
|
|
93
105
|
}
|
|
94
106
|
|
|
95
107
|
override fun onBillingServiceDisconnected() {
|
|
96
|
-
|
|
97
|
-
billingClientCache = null
|
|
98
|
-
promise.reject("initConnection", "Billing service disconnected")
|
|
99
|
-
} catch (oce: ObjectAlreadyConsumedException) {
|
|
100
|
-
Log.e(TAG, oce.message!!)
|
|
101
|
-
}
|
|
108
|
+
Log.i(TAG, "Billing service disconnected")
|
|
102
109
|
}
|
|
103
110
|
})
|
|
104
111
|
}
|
|
105
112
|
|
|
106
113
|
@ReactMethod
|
|
107
114
|
fun endConnection(promise: Promise) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
billingClientCache!!.endConnection()
|
|
111
|
-
null
|
|
112
|
-
} catch (e: Exception) {
|
|
113
|
-
promise.reject("endConnection", e.message)
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
try {
|
|
118
|
-
promise.resolve(true)
|
|
119
|
-
} catch (oce: ObjectAlreadyConsumedException) {
|
|
120
|
-
Log.e(TAG, oce.message!!)
|
|
121
|
-
}
|
|
115
|
+
billingClient.endConnection()
|
|
116
|
+
promise.resolve(true)
|
|
122
117
|
}
|
|
123
118
|
|
|
124
119
|
private fun consumeItems(
|
|
@@ -128,251 +123,236 @@ class RNIapModule(reactContext: ReactApplicationContext) :
|
|
|
128
123
|
) {
|
|
129
124
|
for (purchase in purchases) {
|
|
130
125
|
ensureConnection(
|
|
131
|
-
promise
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
billingClient.consumeAsync(consumeParams, listener)
|
|
126
|
+
promise
|
|
127
|
+
) {
|
|
128
|
+
val consumeParams =
|
|
129
|
+
ConsumeParams.newBuilder().setPurchaseToken(purchase.purchaseToken)
|
|
130
|
+
.build()
|
|
131
|
+
val listener =
|
|
132
|
+
ConsumeResponseListener { billingResult: BillingResult, outToken: String? ->
|
|
133
|
+
if (billingResult.responseCode != expectedResponseCode) {
|
|
134
|
+
PlayUtils.instance
|
|
135
|
+
.rejectPromiseWithBillingError(
|
|
136
|
+
promise,
|
|
137
|
+
billingResult.responseCode
|
|
138
|
+
)
|
|
139
|
+
return@ConsumeResponseListener
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
promise.resolve(true)
|
|
143
|
+
} catch (oce: ObjectAlreadyConsumedException) {
|
|
144
|
+
promise.reject(oce.message)
|
|
145
|
+
}
|
|
154
146
|
}
|
|
155
|
-
|
|
156
|
-
|
|
147
|
+
billingClient.consumeAsync(consumeParams, listener)
|
|
148
|
+
}
|
|
157
149
|
}
|
|
158
150
|
}
|
|
159
151
|
|
|
160
152
|
@ReactMethod
|
|
161
153
|
fun flushFailedPurchasesCachedAsPending(promise: Promise) {
|
|
162
154
|
ensureConnection(
|
|
163
|
-
promise
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
pendingPurchases.add(purchase)
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (pendingPurchases.size == 0) {
|
|
185
|
-
promise.resolve(false)
|
|
186
|
-
return@queryPurchasesAsync
|
|
187
|
-
}
|
|
188
|
-
consumeItems(
|
|
189
|
-
pendingPurchases,
|
|
190
|
-
promise,
|
|
191
|
-
BillingClient.BillingResponseCode.ITEM_NOT_OWNED
|
|
192
|
-
)
|
|
155
|
+
promise
|
|
156
|
+
) {
|
|
157
|
+
val array = WritableNativeArray()
|
|
158
|
+
billingClient.queryPurchasesAsync(
|
|
159
|
+
BillingClient.SkuType.INAPP
|
|
160
|
+
) { _: BillingResult?, list: List<Purchase>? ->
|
|
161
|
+
if (list == null) {
|
|
162
|
+
// No purchases found
|
|
163
|
+
promise.resolve(false)
|
|
164
|
+
return@queryPurchasesAsync
|
|
165
|
+
}
|
|
166
|
+
val pendingPurchases: MutableList<Purchase> = ArrayList()
|
|
167
|
+
for (purchase in list) {
|
|
168
|
+
// we only want to try to consume PENDING items, in order to force cache-refresh
|
|
169
|
+
// for
|
|
170
|
+
// them
|
|
171
|
+
if (purchase.purchaseState == Purchase.PurchaseState.PENDING) {
|
|
172
|
+
pendingPurchases.add(purchase)
|
|
193
173
|
}
|
|
194
174
|
}
|
|
175
|
+
if (pendingPurchases.size == 0) {
|
|
176
|
+
promise.resolve(false)
|
|
177
|
+
return@queryPurchasesAsync
|
|
178
|
+
}
|
|
179
|
+
consumeItems(
|
|
180
|
+
pendingPurchases,
|
|
181
|
+
promise,
|
|
182
|
+
BillingClient.BillingResponseCode.ITEM_NOT_OWNED
|
|
183
|
+
)
|
|
195
184
|
}
|
|
196
|
-
|
|
185
|
+
}
|
|
197
186
|
}
|
|
198
187
|
|
|
199
188
|
@ReactMethod
|
|
200
189
|
fun getItemsByType(type: String?, skuArr: ReadableArray, promise: Promise) {
|
|
201
190
|
ensureConnection(
|
|
202
|
-
promise
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
skus.put(sku.getSku(), sku)
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
val items = WritableNativeArray()
|
|
229
|
-
for (skuDetails in skuDetailsList!!) {
|
|
230
|
-
val item = Arguments.createMap()
|
|
231
|
-
item.putString("productId", skuDetails.sku)
|
|
232
|
-
val introductoryPriceMicros = skuDetails.introductoryPriceAmountMicros
|
|
233
|
-
val priceAmountMicros = skuDetails.priceAmountMicros
|
|
234
|
-
// Use valueOf instead of constructors.
|
|
235
|
-
// See:
|
|
236
|
-
// https://www.javaworld.com/article/2073176/caution--double-to-bigdecimal-in-java.html
|
|
237
|
-
val priceAmount = BigDecimal.valueOf(priceAmountMicros)
|
|
238
|
-
val introductoryPriceAmount =
|
|
239
|
-
BigDecimal.valueOf(introductoryPriceMicros)
|
|
240
|
-
val microUnitsDivisor = BigDecimal.valueOf(1000000)
|
|
241
|
-
val price = priceAmount.divide(microUnitsDivisor).toString()
|
|
242
|
-
val introductoryPriceAsAmountAndroid =
|
|
243
|
-
introductoryPriceAmount.divide(microUnitsDivisor).toString()
|
|
244
|
-
item.putString("price", price)
|
|
245
|
-
item.putString("currency", skuDetails.priceCurrencyCode)
|
|
246
|
-
item.putString("type", skuDetails.type)
|
|
247
|
-
item.putString("localizedPrice", skuDetails.price)
|
|
248
|
-
item.putString("title", skuDetails.title)
|
|
249
|
-
item.putString("description", skuDetails.description)
|
|
250
|
-
item.putString("introductoryPrice", skuDetails.introductoryPrice)
|
|
251
|
-
item.putString("typeAndroid", skuDetails.type)
|
|
252
|
-
item.putString("packageNameAndroid", skuDetails.zzc())
|
|
253
|
-
item.putString("originalPriceAndroid", skuDetails.originalPrice)
|
|
254
|
-
item.putString(
|
|
255
|
-
"subscriptionPeriodAndroid",
|
|
256
|
-
skuDetails.subscriptionPeriod
|
|
257
|
-
)
|
|
258
|
-
item.putString("freeTrialPeriodAndroid", skuDetails.freeTrialPeriod)
|
|
259
|
-
item.putString(
|
|
260
|
-
"introductoryPriceCyclesAndroid",
|
|
261
|
-
skuDetails.introductoryPriceCycles.toString()
|
|
262
|
-
)
|
|
263
|
-
item.putString(
|
|
264
|
-
"introductoryPricePeriodAndroid", skuDetails.introductoryPricePeriod
|
|
265
|
-
)
|
|
266
|
-
item.putString(
|
|
267
|
-
"introductoryPriceAsAmountAndroid", introductoryPriceAsAmountAndroid
|
|
268
|
-
)
|
|
269
|
-
item.putString("iconUrl", skuDetails.iconUrl)
|
|
270
|
-
item.putString("originalJson", skuDetails.originalJson)
|
|
271
|
-
val originalPriceAmountMicros =
|
|
272
|
-
BigDecimal.valueOf(skuDetails.originalPriceAmountMicros)
|
|
273
|
-
val originalPrice =
|
|
274
|
-
originalPriceAmountMicros.divide(microUnitsDivisor).toString()
|
|
275
|
-
item.putString("originalPrice", originalPrice)
|
|
276
|
-
items.pushMap(item)
|
|
277
|
-
}
|
|
278
|
-
try {
|
|
279
|
-
promise.resolve(items)
|
|
280
|
-
} catch (oce: ObjectAlreadyConsumedException) {
|
|
281
|
-
Log.e(TAG, oce.message!!)
|
|
282
|
-
}
|
|
191
|
+
promise
|
|
192
|
+
) {
|
|
193
|
+
val skuList = ArrayList<String>()
|
|
194
|
+
for (i in 0 until skuArr.size()) {
|
|
195
|
+
val sku = skuArr.getString(i)
|
|
196
|
+
if (sku is String) {
|
|
197
|
+
skuList.add(sku)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
val params = SkuDetailsParams.newBuilder()
|
|
201
|
+
params.setSkusList(skuList).setType(type!!)
|
|
202
|
+
billingClient.querySkuDetailsAsync(
|
|
203
|
+
params.build()
|
|
204
|
+
) { billingResult: BillingResult, skuDetailsList: List<SkuDetails>? ->
|
|
205
|
+
Log.d(TAG, "responseCode: " + billingResult.responseCode)
|
|
206
|
+
if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
|
|
207
|
+
PlayUtils.instance
|
|
208
|
+
.rejectPromiseWithBillingError(promise, billingResult.responseCode)
|
|
209
|
+
return@querySkuDetailsAsync
|
|
210
|
+
}
|
|
211
|
+
if (skuDetailsList != null) {
|
|
212
|
+
for (sku in skuDetailsList) {
|
|
213
|
+
skus[sku.sku] = sku
|
|
283
214
|
}
|
|
284
215
|
}
|
|
216
|
+
val items = WritableNativeArray()
|
|
217
|
+
for (skuDetails in skuDetailsList!!) {
|
|
218
|
+
val item = Arguments.createMap()
|
|
219
|
+
item.putString("productId", skuDetails.sku)
|
|
220
|
+
val introductoryPriceMicros = skuDetails.introductoryPriceAmountMicros
|
|
221
|
+
val priceAmountMicros = skuDetails.priceAmountMicros
|
|
222
|
+
// Use valueOf instead of constructors.
|
|
223
|
+
// See:
|
|
224
|
+
// https://www.javaworld.com/article/2073176/caution--double-to-bigdecimal-in-java.html
|
|
225
|
+
val priceAmount = BigDecimal.valueOf(priceAmountMicros)
|
|
226
|
+
val introductoryPriceAmount =
|
|
227
|
+
BigDecimal.valueOf(introductoryPriceMicros)
|
|
228
|
+
val microUnitsDivisor = BigDecimal.valueOf(1000000)
|
|
229
|
+
val price = priceAmount.divide(microUnitsDivisor).toString()
|
|
230
|
+
val introductoryPriceAsAmountAndroid =
|
|
231
|
+
introductoryPriceAmount.divide(microUnitsDivisor).toString()
|
|
232
|
+
item.putString("price", price)
|
|
233
|
+
item.putString("currency", skuDetails.priceCurrencyCode)
|
|
234
|
+
item.putString("type", skuDetails.type)
|
|
235
|
+
item.putString("localizedPrice", skuDetails.price)
|
|
236
|
+
item.putString("title", skuDetails.title)
|
|
237
|
+
item.putString("description", skuDetails.description)
|
|
238
|
+
item.putString("introductoryPrice", skuDetails.introductoryPrice)
|
|
239
|
+
item.putString("typeAndroid", skuDetails.type)
|
|
240
|
+
item.putString("packageNameAndroid", skuDetails.zzc())
|
|
241
|
+
item.putString("originalPriceAndroid", skuDetails.originalPrice)
|
|
242
|
+
item.putString(
|
|
243
|
+
"subscriptionPeriodAndroid",
|
|
244
|
+
skuDetails.subscriptionPeriod
|
|
245
|
+
)
|
|
246
|
+
item.putString("freeTrialPeriodAndroid", skuDetails.freeTrialPeriod)
|
|
247
|
+
item.putString(
|
|
248
|
+
"introductoryPriceCyclesAndroid",
|
|
249
|
+
skuDetails.introductoryPriceCycles.toString()
|
|
250
|
+
)
|
|
251
|
+
item.putString(
|
|
252
|
+
"introductoryPricePeriodAndroid", skuDetails.introductoryPricePeriod
|
|
253
|
+
)
|
|
254
|
+
item.putString(
|
|
255
|
+
"introductoryPriceAsAmountAndroid", introductoryPriceAsAmountAndroid
|
|
256
|
+
)
|
|
257
|
+
item.putString("iconUrl", skuDetails.iconUrl)
|
|
258
|
+
item.putString("originalJson", skuDetails.originalJson)
|
|
259
|
+
val originalPriceAmountMicros =
|
|
260
|
+
BigDecimal.valueOf(skuDetails.originalPriceAmountMicros)
|
|
261
|
+
val originalPrice =
|
|
262
|
+
originalPriceAmountMicros.divide(microUnitsDivisor).toString()
|
|
263
|
+
item.putString("originalPrice", originalPrice)
|
|
264
|
+
items.pushMap(item)
|
|
265
|
+
}
|
|
266
|
+
try {
|
|
267
|
+
promise.resolve(items)
|
|
268
|
+
} catch (oce: ObjectAlreadyConsumedException) {
|
|
269
|
+
Log.e(TAG, oce.message!!)
|
|
270
|
+
}
|
|
285
271
|
}
|
|
286
|
-
|
|
272
|
+
}
|
|
287
273
|
}
|
|
288
274
|
|
|
289
275
|
@ReactMethod
|
|
290
276
|
fun getAvailableItemsByType(type: String, promise: Promise) {
|
|
291
277
|
ensureConnection(
|
|
292
|
-
promise
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
item.putBoolean("autoRenewingAndroid", purchase.isAutoRenewing)
|
|
324
|
-
}
|
|
325
|
-
items.pushMap(item)
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
try {
|
|
329
|
-
promise.resolve(items)
|
|
330
|
-
} catch (oce: ObjectAlreadyConsumedException) {
|
|
331
|
-
Log.e(TAG, oce.message!!)
|
|
278
|
+
promise
|
|
279
|
+
) {
|
|
280
|
+
val items = WritableNativeArray()
|
|
281
|
+
billingClient.queryPurchasesAsync(
|
|
282
|
+
if (type == "subs") BillingClient.SkuType.SUBS else BillingClient.SkuType.INAPP
|
|
283
|
+
) { billingResult: BillingResult?, purchases: List<Purchase>? ->
|
|
284
|
+
if (purchases != null) {
|
|
285
|
+
for (i in purchases.indices) {
|
|
286
|
+
val purchase = purchases[i]
|
|
287
|
+
val item = WritableNativeMap()
|
|
288
|
+
item.putString("productId", purchase.skus[0])
|
|
289
|
+
item.putString("transactionId", purchase.orderId)
|
|
290
|
+
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
291
|
+
item.putString("transactionReceipt", purchase.originalJson)
|
|
292
|
+
item.putString("orderId", purchase.orderId)
|
|
293
|
+
item.putString("purchaseToken", purchase.purchaseToken)
|
|
294
|
+
item.putString("developerPayloadAndroid", purchase.developerPayload)
|
|
295
|
+
item.putString("signatureAndroid", purchase.signature)
|
|
296
|
+
item.putInt("purchaseStateAndroid", purchase.purchaseState)
|
|
297
|
+
item.putBoolean("isAcknowledgedAndroid", purchase.isAcknowledged)
|
|
298
|
+
item.putString("packageNameAndroid", purchase.packageName)
|
|
299
|
+
item.putString(
|
|
300
|
+
"obfuscatedAccountIdAndroid",
|
|
301
|
+
purchase.accountIdentifiers!!.obfuscatedAccountId
|
|
302
|
+
)
|
|
303
|
+
item.putString(
|
|
304
|
+
"obfuscatedProfileIdAndroid",
|
|
305
|
+
purchase.accountIdentifiers!!.obfuscatedProfileId
|
|
306
|
+
)
|
|
307
|
+
if (type == BillingClient.SkuType.SUBS) {
|
|
308
|
+
item.putBoolean("autoRenewingAndroid", purchase.isAutoRenewing)
|
|
332
309
|
}
|
|
310
|
+
items.pushMap(item)
|
|
333
311
|
}
|
|
334
312
|
}
|
|
313
|
+
try {
|
|
314
|
+
promise.resolve(items)
|
|
315
|
+
} catch (oce: ObjectAlreadyConsumedException) {
|
|
316
|
+
Log.e(TAG, oce.message!!)
|
|
317
|
+
}
|
|
335
318
|
}
|
|
336
|
-
|
|
319
|
+
}
|
|
337
320
|
}
|
|
338
321
|
|
|
339
322
|
@ReactMethod
|
|
340
323
|
fun getPurchaseHistoryByType(type: String, promise: Promise) {
|
|
341
324
|
ensureConnection(
|
|
342
|
-
promise
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
Log.e(TAG, oce.message!!)
|
|
371
|
-
}
|
|
372
|
-
}
|
|
325
|
+
promise
|
|
326
|
+
) {
|
|
327
|
+
billingClient.queryPurchaseHistoryAsync(
|
|
328
|
+
if (type == "subs") BillingClient.SkuType.SUBS else BillingClient.SkuType.INAPP
|
|
329
|
+
) { billingResult, purchaseHistoryRecordList ->
|
|
330
|
+
if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
|
|
331
|
+
PlayUtils.instance
|
|
332
|
+
.rejectPromiseWithBillingError(promise, billingResult.responseCode)
|
|
333
|
+
return@queryPurchaseHistoryAsync
|
|
334
|
+
}
|
|
335
|
+
Log.d(TAG, purchaseHistoryRecordList.toString())
|
|
336
|
+
val items = Arguments.createArray()
|
|
337
|
+
for (i in purchaseHistoryRecordList!!.indices) {
|
|
338
|
+
val item = Arguments.createMap()
|
|
339
|
+
val purchase = purchaseHistoryRecordList[i]
|
|
340
|
+
item.putString("productId", purchase.skus[0])
|
|
341
|
+
item.putDouble("transactionDate", purchase.purchaseTime.toDouble())
|
|
342
|
+
item.putString("transactionReceipt", purchase.originalJson)
|
|
343
|
+
item.putString("purchaseToken", purchase.purchaseToken)
|
|
344
|
+
item.putString("dataAndroid", purchase.originalJson)
|
|
345
|
+
item.putString("signatureAndroid", purchase.signature)
|
|
346
|
+
item.putString("developerPayload", purchase.developerPayload)
|
|
347
|
+
items.pushMap(item)
|
|
348
|
+
}
|
|
349
|
+
try {
|
|
350
|
+
promise.resolve(items)
|
|
351
|
+
} catch (oce: ObjectAlreadyConsumedException) {
|
|
352
|
+
Log.e(TAG, oce.message!!)
|
|
373
353
|
}
|
|
374
354
|
}
|
|
375
|
-
|
|
355
|
+
}
|
|
376
356
|
}
|
|
377
357
|
|
|
378
358
|
@ReactMethod
|
|
@@ -391,17 +371,49 @@ class RNIapModule(reactContext: ReactApplicationContext) :
|
|
|
391
371
|
return
|
|
392
372
|
}
|
|
393
373
|
ensureConnection(
|
|
394
|
-
promise
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
374
|
+
promise
|
|
375
|
+
) {
|
|
376
|
+
DoobooUtils.instance.addPromiseForKey(
|
|
377
|
+
PROMISE_BUY_ITEM, promise
|
|
378
|
+
)
|
|
379
|
+
val builder = BillingFlowParams.newBuilder()
|
|
380
|
+
val selectedSku: SkuDetails? = skus[sku]
|
|
381
|
+
if (selectedSku == null) {
|
|
382
|
+
val debugMessage =
|
|
383
|
+
"The sku was not found. Please fetch products first by calling getItems"
|
|
384
|
+
val error = Arguments.createMap()
|
|
385
|
+
error.putString("debugMessage", debugMessage)
|
|
386
|
+
error.putString("code", PROMISE_BUY_ITEM)
|
|
387
|
+
error.putString("message", debugMessage)
|
|
388
|
+
error.putString("productId", sku)
|
|
389
|
+
sendEvent(reactContext, "purchase-error", error)
|
|
390
|
+
promise.reject(PROMISE_BUY_ITEM, debugMessage)
|
|
391
|
+
return@ensureConnection
|
|
392
|
+
}
|
|
393
|
+
builder.setSkuDetails(selectedSku)
|
|
394
|
+
val subscriptionUpdateParamsBuilder = SubscriptionUpdateParams.newBuilder()
|
|
395
|
+
if (purchaseToken != null) {
|
|
396
|
+
subscriptionUpdateParamsBuilder.setOldSkuPurchaseToken(purchaseToken)
|
|
397
|
+
}
|
|
398
|
+
if (obfuscatedAccountId != null) {
|
|
399
|
+
builder.setObfuscatedAccountId(obfuscatedAccountId)
|
|
400
|
+
}
|
|
401
|
+
if (obfuscatedProfileId != null) {
|
|
402
|
+
builder.setObfuscatedProfileId(obfuscatedProfileId)
|
|
403
|
+
}
|
|
404
|
+
if (prorationMode != null && prorationMode != -1) {
|
|
405
|
+
if (prorationMode
|
|
406
|
+
== BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
407
|
+
) {
|
|
408
|
+
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
409
|
+
BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
399
410
|
)
|
|
400
|
-
|
|
401
|
-
var selectedSku: SkuDetails? = skus.get(sku)
|
|
402
|
-
if (selectedSku == null) {
|
|
411
|
+
if (type != BillingClient.SkuType.SUBS) {
|
|
403
412
|
val debugMessage =
|
|
404
|
-
|
|
413
|
+
(
|
|
414
|
+
"IMMEDIATE_AND_CHARGE_PRORATED_PRICE for proration mode only works in" +
|
|
415
|
+
" subscription purchase."
|
|
416
|
+
)
|
|
405
417
|
val error = Arguments.createMap()
|
|
406
418
|
error.putString("debugMessage", debugMessage)
|
|
407
419
|
error.putString("code", PROMISE_BUY_ITEM)
|
|
@@ -409,80 +421,45 @@ class RNIapModule(reactContext: ReactApplicationContext) :
|
|
|
409
421
|
error.putString("productId", sku)
|
|
410
422
|
sendEvent(reactContext, "purchase-error", error)
|
|
411
423
|
promise.reject(PROMISE_BUY_ITEM, debugMessage)
|
|
412
|
-
return
|
|
413
|
-
}
|
|
414
|
-
builder.setSkuDetails(selectedSku)
|
|
415
|
-
val subscriptionUpdateParamsBuilder = SubscriptionUpdateParams.newBuilder()
|
|
416
|
-
if (purchaseToken != null) {
|
|
417
|
-
subscriptionUpdateParamsBuilder.setOldSkuPurchaseToken(purchaseToken)
|
|
418
|
-
}
|
|
419
|
-
if (obfuscatedAccountId != null) {
|
|
420
|
-
builder.setObfuscatedAccountId(obfuscatedAccountId)
|
|
421
|
-
}
|
|
422
|
-
if (obfuscatedProfileId != null) {
|
|
423
|
-
builder.setObfuscatedProfileId(obfuscatedProfileId)
|
|
424
|
-
}
|
|
425
|
-
if (prorationMode != null && prorationMode != -1) {
|
|
426
|
-
if (prorationMode
|
|
427
|
-
== BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
428
|
-
) {
|
|
429
|
-
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
430
|
-
BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE
|
|
431
|
-
)
|
|
432
|
-
if (type != BillingClient.SkuType.SUBS) {
|
|
433
|
-
val debugMessage =
|
|
434
|
-
(
|
|
435
|
-
"IMMEDIATE_AND_CHARGE_PRORATED_PRICE for proration mode only works in" +
|
|
436
|
-
" subscription purchase."
|
|
437
|
-
)
|
|
438
|
-
val error = Arguments.createMap()
|
|
439
|
-
error.putString("debugMessage", debugMessage)
|
|
440
|
-
error.putString("code", PROMISE_BUY_ITEM)
|
|
441
|
-
error.putString("message", debugMessage)
|
|
442
|
-
error.putString("productId", sku)
|
|
443
|
-
sendEvent(reactContext, "purchase-error", error)
|
|
444
|
-
promise.reject(PROMISE_BUY_ITEM, debugMessage)
|
|
445
|
-
return
|
|
446
|
-
}
|
|
447
|
-
} else if (prorationMode
|
|
448
|
-
== BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
449
|
-
) {
|
|
450
|
-
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
451
|
-
BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
452
|
-
)
|
|
453
|
-
} else if (prorationMode == BillingFlowParams.ProrationMode.DEFERRED) {
|
|
454
|
-
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
455
|
-
BillingFlowParams.ProrationMode.DEFERRED
|
|
456
|
-
)
|
|
457
|
-
} else if (prorationMode
|
|
458
|
-
== BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION
|
|
459
|
-
) {
|
|
460
|
-
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
461
|
-
BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
462
|
-
)
|
|
463
|
-
} else if (prorationMode
|
|
464
|
-
== BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
|
|
465
|
-
) {
|
|
466
|
-
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
467
|
-
BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
|
|
468
|
-
)
|
|
469
|
-
} else {
|
|
470
|
-
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
471
|
-
BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY
|
|
472
|
-
)
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
if (purchaseToken != null) {
|
|
476
|
-
val subscriptionUpdateParams = subscriptionUpdateParamsBuilder.build()
|
|
477
|
-
builder.setSubscriptionUpdateParams(subscriptionUpdateParams)
|
|
424
|
+
return@ensureConnection
|
|
478
425
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
426
|
+
} else if (prorationMode
|
|
427
|
+
== BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
428
|
+
) {
|
|
429
|
+
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
430
|
+
BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
431
|
+
)
|
|
432
|
+
} else if (prorationMode == BillingFlowParams.ProrationMode.DEFERRED) {
|
|
433
|
+
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
434
|
+
BillingFlowParams.ProrationMode.DEFERRED
|
|
435
|
+
)
|
|
436
|
+
} else if (prorationMode
|
|
437
|
+
== BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION
|
|
438
|
+
) {
|
|
439
|
+
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
440
|
+
BillingFlowParams.ProrationMode.IMMEDIATE_WITHOUT_PRORATION
|
|
441
|
+
)
|
|
442
|
+
} else if (prorationMode
|
|
443
|
+
== BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
|
|
444
|
+
) {
|
|
445
|
+
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
446
|
+
BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE
|
|
447
|
+
)
|
|
448
|
+
} else {
|
|
449
|
+
subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(
|
|
450
|
+
BillingFlowParams.ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY
|
|
451
|
+
)
|
|
483
452
|
}
|
|
484
453
|
}
|
|
485
|
-
|
|
454
|
+
if (purchaseToken != null) {
|
|
455
|
+
val subscriptionUpdateParams = subscriptionUpdateParamsBuilder.build()
|
|
456
|
+
builder.setSubscriptionUpdateParams(subscriptionUpdateParams)
|
|
457
|
+
}
|
|
458
|
+
val flowParams = builder.build()
|
|
459
|
+
val billingResult = billingClient.launchBillingFlow(activity, flowParams)
|
|
460
|
+
val errorData: Array<String?> =
|
|
461
|
+
PlayUtils.instance.getBillingResponseData(billingResult.responseCode)
|
|
462
|
+
}
|
|
486
463
|
}
|
|
487
464
|
|
|
488
465
|
@ReactMethod
|
|
@@ -492,36 +469,33 @@ class RNIapModule(reactContext: ReactApplicationContext) :
|
|
|
492
469
|
promise: Promise
|
|
493
470
|
) {
|
|
494
471
|
ensureConnection(
|
|
495
|
-
promise
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
Log.e(TAG, oce.message!!)
|
|
520
|
-
}
|
|
521
|
-
}
|
|
472
|
+
promise
|
|
473
|
+
) {
|
|
474
|
+
val acknowledgePurchaseParams =
|
|
475
|
+
AcknowledgePurchaseParams.newBuilder().setPurchaseToken(
|
|
476
|
+
token!!
|
|
477
|
+
).build()
|
|
478
|
+
billingClient.acknowledgePurchase(
|
|
479
|
+
acknowledgePurchaseParams
|
|
480
|
+
) { billingResult: BillingResult ->
|
|
481
|
+
if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
|
|
482
|
+
PlayUtils.instance
|
|
483
|
+
.rejectPromiseWithBillingError(promise, billingResult.responseCode)
|
|
484
|
+
}
|
|
485
|
+
try {
|
|
486
|
+
val map = Arguments.createMap()
|
|
487
|
+
map.putInt("responseCode", billingResult.responseCode)
|
|
488
|
+
map.putString("debugMessage", billingResult.debugMessage)
|
|
489
|
+
val errorData: Array<String?> = PlayUtils.instance
|
|
490
|
+
.getBillingResponseData(billingResult.responseCode)
|
|
491
|
+
map.putString("code", errorData[0])
|
|
492
|
+
map.putString("message", errorData[1])
|
|
493
|
+
promise.resolve(map)
|
|
494
|
+
} catch (oce: ObjectAlreadyConsumedException) {
|
|
495
|
+
Log.e(TAG, oce.message!!)
|
|
522
496
|
}
|
|
523
497
|
}
|
|
524
|
-
|
|
498
|
+
}
|
|
525
499
|
}
|
|
526
500
|
|
|
527
501
|
@ReactMethod
|
|
@@ -532,32 +506,29 @@ class RNIapModule(reactContext: ReactApplicationContext) :
|
|
|
532
506
|
) {
|
|
533
507
|
val params = ConsumeParams.newBuilder().setPurchaseToken(token!!).build()
|
|
534
508
|
ensureConnection(
|
|
535
|
-
promise
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
promise.reject(oce.message)
|
|
556
|
-
}
|
|
557
|
-
}
|
|
509
|
+
promise
|
|
510
|
+
) {
|
|
511
|
+
billingClient.consumeAsync(
|
|
512
|
+
params
|
|
513
|
+
) { billingResult: BillingResult, purchaseToken: String? ->
|
|
514
|
+
if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
|
|
515
|
+
PlayUtils.instance
|
|
516
|
+
.rejectPromiseWithBillingError(promise, billingResult.responseCode)
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
val map = Arguments.createMap()
|
|
520
|
+
map.putInt("responseCode", billingResult.responseCode)
|
|
521
|
+
map.putString("debugMessage", billingResult.debugMessage)
|
|
522
|
+
val errorData: Array<String?> = PlayUtils.instance
|
|
523
|
+
.getBillingResponseData(billingResult.responseCode)
|
|
524
|
+
map.putString("code", errorData[0])
|
|
525
|
+
map.putString("message", errorData[1])
|
|
526
|
+
promise.resolve(map)
|
|
527
|
+
} catch (oce: ObjectAlreadyConsumedException) {
|
|
528
|
+
promise.reject(oce.message)
|
|
558
529
|
}
|
|
559
530
|
}
|
|
560
|
-
|
|
531
|
+
}
|
|
561
532
|
}
|
|
562
533
|
|
|
563
534
|
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
|
|
@@ -625,30 +596,25 @@ class RNIapModule(reactContext: ReactApplicationContext) :
|
|
|
625
596
|
|
|
626
597
|
private fun sendUnconsumedPurchases(promise: Promise) {
|
|
627
598
|
ensureConnection(
|
|
628
|
-
promise
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
for (purchase in list!!) {
|
|
641
|
-
if (!purchase.isAcknowledged) {
|
|
642
|
-
unacknowledgedPurchases.add(purchase)
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
onPurchasesUpdated(billingResult, unacknowledgedPurchases)
|
|
599
|
+
promise
|
|
600
|
+
) {
|
|
601
|
+
val types = arrayOf(BillingClient.SkuType.INAPP, BillingClient.SkuType.SUBS)
|
|
602
|
+
for (type in types) {
|
|
603
|
+
billingClient.queryPurchasesAsync(
|
|
604
|
+
type
|
|
605
|
+
) { billingResult: BillingResult, list: List<Purchase>? ->
|
|
606
|
+
val unacknowledgedPurchases = ArrayList<Purchase>()
|
|
607
|
+
|
|
608
|
+
for (purchase in list!!) {
|
|
609
|
+
if (!purchase.isAcknowledged) {
|
|
610
|
+
unacknowledgedPurchases.add(purchase)
|
|
646
611
|
}
|
|
647
612
|
}
|
|
648
|
-
|
|
613
|
+
onPurchasesUpdated(billingResult, unacknowledgedPurchases)
|
|
649
614
|
}
|
|
650
615
|
}
|
|
651
|
-
|
|
616
|
+
promise.resolve(true)
|
|
617
|
+
}
|
|
652
618
|
}
|
|
653
619
|
|
|
654
620
|
@ReactMethod
|
|
@@ -682,19 +648,15 @@ class RNIapModule(reactContext: ReactApplicationContext) :
|
|
|
682
648
|
|
|
683
649
|
companion object {
|
|
684
650
|
private const val PROMISE_BUY_ITEM = "PROMISE_BUY_ITEM"
|
|
651
|
+
const val TAG = "RNIapModule"
|
|
685
652
|
}
|
|
686
653
|
|
|
687
654
|
init {
|
|
688
|
-
this.reactContext = reactContext
|
|
689
|
-
skus = mutableMapOf<String, SkuDetails>()
|
|
690
655
|
val lifecycleEventListener: LifecycleEventListener = object : LifecycleEventListener {
|
|
691
656
|
override fun onHostResume() {}
|
|
692
657
|
override fun onHostPause() {}
|
|
693
658
|
override fun onHostDestroy() {
|
|
694
|
-
|
|
695
|
-
billingClientCache!!.endConnection()
|
|
696
|
-
billingClientCache = null
|
|
697
|
-
}
|
|
659
|
+
billingClient.endConnection()
|
|
698
660
|
}
|
|
699
661
|
}
|
|
700
662
|
reactContext.addLifecycleEventListener(lifecycleEventListener)
|