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