|
@@ -1,29 +1,38 @@
|
|
|
package cn.yyxx.eyuancomm.core.impl
|
|
|
|
|
|
import android.app.Activity
|
|
|
-import android.text.TextUtils
|
|
|
import cn.yyxx.eyuancomm.comm.entity.SdkChargeInfo
|
|
|
-import cn.yyxx.eyuancomm.comm.network.SdkRequest
|
|
|
import cn.yyxx.eyuancomm.comm.utils.Logger
|
|
|
-import cn.yyxx.eyuancomm.comm.utils.MMKVHandler
|
|
|
+import cn.yyxx.eyuancomm.core.internal.IOrder
|
|
|
import cn.yyxx.support.ResUtils
|
|
|
import cn.yyxx.support.hawkeye.ToastUtils
|
|
|
import com.android.billingclient.api.*
|
|
|
import com.google.android.gms.common.ConnectionResult
|
|
|
import com.google.android.gms.common.GoogleApiAvailability
|
|
|
-import org.json.JSONException
|
|
|
import org.json.JSONObject
|
|
|
|
|
|
/**
|
|
|
* @author #Suyghur.
|
|
|
* Created on 2021/06/17
|
|
|
*/
|
|
|
- class InAppBilling {
|
|
|
+internal class InAppBilling : PurchasesUpdatedListener {
|
|
|
|
|
|
- private lateinit var billingClient: BillingClient
|
|
|
+ private var billingClient: BillingClient? = null
|
|
|
|
|
|
- private lateinit var callback: InAppBillingCallback
|
|
|
- private lateinit var chargeInfo: SdkChargeInfo
|
|
|
+ private var callback: InAppBillingCallback? = null
|
|
|
+
|
|
|
+ private val consumeHandler = object : IOrder {
|
|
|
+ override fun onConsume(activity: Activity, chargeInfo: SdkChargeInfo, token: String, cache: Boolean) {
|
|
|
+ if (cache) {
|
|
|
+ consumeCacheOrder(activity, chargeInfo, token)
|
|
|
+ } else {
|
|
|
+ consumeOrder(activity, chargeInfo, token)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ override fun onFinish() {
|
|
|
+ disConnection()
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
companion object {
|
|
|
val instance: InAppBilling by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
|
@@ -33,80 +42,43 @@ import org.json.JSONObject
|
|
|
|
|
|
fun charge(activity: Activity, chargeInfo: SdkChargeInfo, callback: InAppBillingCallback) {
|
|
|
this.callback = callback
|
|
|
- this.chargeInfo = chargeInfo
|
|
|
if (checkGoogleApiAvailability(activity)) {
|
|
|
- createOrder(activity)
|
|
|
+ initializeBillingClient(activity)
|
|
|
+ connectGooglePlay(activity, chargeInfo)
|
|
|
} else {
|
|
|
ToastUtils.toastInfo(activity, "Your phone or Google account does not support In-app Billing")
|
|
|
- callback.onResult(-1, "谷歌iab支付服务不可用")
|
|
|
+ callback.onResult(-1, "谷歌iab支付服务不可用", consumeHandler)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 获取订单号
|
|
|
- */
|
|
|
- private fun createOrder(activity: Activity) {
|
|
|
- Logger.d("order_id ---> ${chargeInfo.orderId}")
|
|
|
- Logger.d("payment ---> ${chargeInfo.payment}")
|
|
|
- when (chargeInfo.payment) {
|
|
|
- 1 -> {
|
|
|
- // 获取订单号成功,初始化IAB收银台客户端
|
|
|
- Logger.d("获取订单号成功,初始化IAB收银台客户端")
|
|
|
- initializeBillingClient(activity)
|
|
|
- connectGooglePlay(activity, false)
|
|
|
- }
|
|
|
- 3 -> {
|
|
|
- // 切换第三方支付
|
|
|
- callback.onResult(1, "切换第三方支付")
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
* 初始化IAB收银台客户端
|
|
|
*/
|
|
|
private fun initializeBillingClient(activity: Activity) {
|
|
|
- billingClient = BillingClient.newBuilder(activity).setListener { billingResult, list ->
|
|
|
- //谷歌支付结果在这里回调
|
|
|
- billingResult.log("onPurchasesUpdated")
|
|
|
- if (billingResult.isOk()) {
|
|
|
- if (list.isNullOrEmpty()) {
|
|
|
- disConnection()
|
|
|
- callback.onResult(-1, "支付失败")
|
|
|
- } else {
|
|
|
- list.forEach { purchase ->
|
|
|
- notifyOrder2Backend(activity, chargeInfo.orderId, purchase, false)
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- disConnection()
|
|
|
- callback.onResult(-1, "支付失败")
|
|
|
- }
|
|
|
- }.enablePendingPurchases().build()
|
|
|
+ billingClient = BillingClient.newBuilder(activity).setListener(this).enablePendingPurchases().build()
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 连接谷歌商店
|
|
|
*/
|
|
|
- private fun connectGooglePlay(activity: Activity, isPreReward: Boolean = false) {
|
|
|
- billingClient.apply {
|
|
|
+ private fun connectGooglePlay(activity: Activity, chargeInfo: SdkChargeInfo) {
|
|
|
+ billingClient?.apply {
|
|
|
Logger.d("start connection Google Play ...")
|
|
|
startConnection(object : BillingClientStateListener {
|
|
|
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
|
|
billingResult.log("onBillingSetupFinished")
|
|
|
if (billingResult.isOk()) {
|
|
|
- queryChargeInfo(activity)
|
|
|
+ queryChargeInfo(activity, chargeInfo)
|
|
|
} else {
|
|
|
+ callback?.onResult(-1, "连接谷歌商店失败", consumeHandler)
|
|
|
disConnection()
|
|
|
- callback.onResult(-1, "连接谷歌商店失败")
|
|
|
}
|
|
|
}
|
|
|
|
|
|
override fun onBillingServiceDisconnected() {
|
|
|
Logger.e("onBillingServiceDisconnected")
|
|
|
- connectGooglePlay(activity, isPreReward)
|
|
|
+ connectGooglePlay(activity, chargeInfo)
|
|
|
}
|
|
|
})
|
|
|
}
|
|
@@ -115,21 +87,23 @@ import org.json.JSONObject
|
|
|
/**
|
|
|
* 查询未消耗订单
|
|
|
*/
|
|
|
- private fun queryChargeInfo(activity: Activity) {
|
|
|
- billingClient.apply {
|
|
|
+ private fun queryChargeInfo(activity: Activity, chargeInfo: SdkChargeInfo) {
|
|
|
+ billingClient?.apply {
|
|
|
val list = queryPurchases(BillingClient.SkuType.INAPP).purchasesList
|
|
|
if (list.isNullOrEmpty()) {
|
|
|
//正常发起支付流程
|
|
|
- querySkuDetails(activity)
|
|
|
+ querySkuDetails(activity, chargeInfo)
|
|
|
} else {
|
|
|
Logger.e("存在未消耗订单,发起补单流程,size : ${list.size}")
|
|
|
if (list.isNullOrEmpty()) {
|
|
|
//发起正常支付流程
|
|
|
- querySkuDetails(activity)
|
|
|
+ querySkuDetails(activity, chargeInfo)
|
|
|
} else {
|
|
|
- list.forEach { purchase ->
|
|
|
- consumeCacheOrder(activity, purchase)
|
|
|
- }
|
|
|
+ val purchase = list[0]
|
|
|
+ val jsonObject = JSONObject()
|
|
|
+ jsonObject.put("order_id", purchase.accountIdentifiers?.obfuscatedAccountId)
|
|
|
+ jsonObject.put("order_notify_data", purchase.originalJson)
|
|
|
+ callback?.onResult(2, jsonObject.toString(), consumeHandler)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -138,167 +112,113 @@ import org.json.JSONObject
|
|
|
/**
|
|
|
* 查询商品信息
|
|
|
*/
|
|
|
- private fun querySkuDetails(activity: Activity) {
|
|
|
+ private fun querySkuDetails(activity: Activity, chargeInfo: SdkChargeInfo) {
|
|
|
val skus = mutableListOf<String>()
|
|
|
skus.add(chargeInfo.productId)
|
|
|
val params = SkuDetailsParams.newBuilder().setType(BillingClient.SkuType.INAPP).setSkusList(skus).build()
|
|
|
- billingClient.querySkuDetailsAsync(params) { billingResult, list ->
|
|
|
+ billingClient?.querySkuDetailsAsync(params) { billingResult, list ->
|
|
|
billingResult.log("onSkuDetailsResponse")
|
|
|
if (list.isNullOrEmpty()) {
|
|
|
//查询商品信息失败
|
|
|
Logger.e("查询商品信息失败")
|
|
|
ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
- callback.onResult(-1, "查询商品信息失败")
|
|
|
+ callback?.onResult(-1, "查询商品信息失败", consumeHandler)
|
|
|
disConnection()
|
|
|
} else {
|
|
|
if (list.size == 1) {
|
|
|
val skuDetails = list[0]
|
|
|
Logger.d("product id : ${skuDetails.sku}")
|
|
|
- launchBillingFlow(activity, skuDetails)
|
|
|
+ launchBillingFlow(activity, chargeInfo, skuDetails)
|
|
|
} else {
|
|
|
ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
- callback.onResult(-1, "查询商品信息异常")
|
|
|
+ callback?.onResult(-1, "查询商品信息异常", consumeHandler)
|
|
|
disConnection()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 消耗订单
|
|
|
- */
|
|
|
- private fun consumeAsync(activity: Activity, purchase: Purchase, isCache: Boolean = false) {
|
|
|
- val consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchase.purchaseToken).build()
|
|
|
- billingClient.apply {
|
|
|
- if (isReady) {
|
|
|
- consumeAsync(consumeParams) { billingResult, _ ->
|
|
|
- billingResult.log("onConsumeResponse")
|
|
|
- if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
|
|
- if (isCache) {
|
|
|
- querySkuDetails(activity)
|
|
|
- } else {
|
|
|
- callback.onResult(0, "支付成功")
|
|
|
- disConnection()
|
|
|
- }
|
|
|
- removeOrderInfo(purchase.orderId)
|
|
|
- } else {
|
|
|
- callback.onResult(-1, "消耗订单异常")
|
|
|
- disConnection()
|
|
|
- ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- disConnection()
|
|
|
- callback.onResult(-1, "消耗订单异常")
|
|
|
- ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* 启动收银台
|
|
|
*/
|
|
|
- private fun launchBillingFlow(activity: Activity, skuDetails: SkuDetails) {
|
|
|
- billingClient.apply {
|
|
|
+ private fun launchBillingFlow(activity: Activity, chargeInfo: SdkChargeInfo, skuDetails: SkuDetails) {
|
|
|
+ billingClient?.apply {
|
|
|
if (isReady) {
|
|
|
val flowParams = BillingFlowParams.newBuilder().setObfuscatedAccountId(chargeInfo.orderId).setSkuDetails(skuDetails).build()
|
|
|
val billingResult = launchBillingFlow(activity, flowParams)
|
|
|
billingResult.log("launchBillingFlow")
|
|
|
- if (billingResult.isOk()) {
|
|
|
- disConnection()
|
|
|
+ if (!billingResult.isOk()) {
|
|
|
ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
- callback.onResult(-1, "启动谷歌收银台失败")
|
|
|
+ callback?.onResult(-1, "启动谷歌收银台失败", consumeHandler)
|
|
|
+ disConnection()
|
|
|
}
|
|
|
} else {
|
|
|
- disConnection()
|
|
|
ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
- callback.onResult(-1, "启动谷歌收银台失败")
|
|
|
+ callback?.onResult(-1, "启动谷歌收银台失败", consumeHandler)
|
|
|
+ disConnection()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 通知服务端发货
|
|
|
+ * 消耗订单
|
|
|
*/
|
|
|
- private fun notifyOrder2Backend(activity: Activity, orderId: String, purchase: Purchase, isCache: Boolean = false) {
|
|
|
- val jsonObject = JSONObject()
|
|
|
- jsonObject.put("order_id", orderId)
|
|
|
- jsonObject.put("order_notify_data", purchase.originalJson)
|
|
|
- SdkRequest.instance.notifyOrder(activity, jsonObject) { resultInfo ->
|
|
|
- when (resultInfo.code) {
|
|
|
- 1 -> {
|
|
|
- //消耗订单
|
|
|
- consumeAsync(activity, purchase, isCache)
|
|
|
- }
|
|
|
- 2 -> {
|
|
|
- Logger.d(resultInfo.msg)
|
|
|
- consumeAsync(activity, purchase, isCache)
|
|
|
- }
|
|
|
- else -> {
|
|
|
- //失败则缓存订单
|
|
|
- saveOrderInfo(purchase.orderId, orderId)
|
|
|
- disConnection()
|
|
|
- val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
|
|
|
- ResUtils.getResString(activity, "yyxx_charge_tv_error")
|
|
|
+ fun consumeOrder(activity: Activity, chargeInfo: SdkChargeInfo, token: String) {
|
|
|
+ val consumeParams = ConsumeParams.newBuilder().setPurchaseToken(token).build()
|
|
|
+ billingClient?.apply {
|
|
|
+ if (isReady) {
|
|
|
+ consumeAsync(consumeParams) { billingResult, _ ->
|
|
|
+ billingResult.log("onConsumeResponse")
|
|
|
+ if (billingResult.isOk()) {
|
|
|
+ callback?.onResult(0, "支付流程完成", consumeHandler)
|
|
|
+ disConnection()
|
|
|
} else {
|
|
|
- resultInfo.msg
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
+ callback?.onResult(-1, "消耗订单异常", consumeHandler)
|
|
|
+ disConnection()
|
|
|
}
|
|
|
- ToastUtils.toastInfo(activity, msg)
|
|
|
- callback.onResult(-1, "发货失败")
|
|
|
}
|
|
|
+ } else {
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
+ callback?.onResult(-1, "消耗订单异常", consumeHandler)
|
|
|
+ disConnection()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 消耗缓存订单
|
|
|
- */
|
|
|
- private fun consumeCacheOrder(activity: Activity, purchase: Purchase) {
|
|
|
- // 消耗完了再发起支付
|
|
|
- Logger.d("消耗缓存订单 : $purchase")
|
|
|
- var orderId = ""
|
|
|
- purchase.accountIdentifiers?.apply {
|
|
|
- orderId = if (!TextUtils.isEmpty(obfuscatedAccountId)) {
|
|
|
- obfuscatedAccountId!!
|
|
|
+ fun consumeCacheOrder(activity: Activity, chargeInfo: SdkChargeInfo, token: String) {
|
|
|
+ val consumeParams = ConsumeParams.newBuilder().setPurchaseToken(token).build()
|
|
|
+ billingClient?.apply {
|
|
|
+ if (isReady) {
|
|
|
+ consumeAsync(consumeParams) { billingResult, _ ->
|
|
|
+ billingResult.log("onConsumeResponse")
|
|
|
+ if (billingResult.isOk()) {
|
|
|
+ querySkuDetails(activity, chargeInfo)
|
|
|
+ } else {
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
+ callback?.onResult(-1, "消耗订单异常", consumeHandler)
|
|
|
+ disConnection()
|
|
|
+ }
|
|
|
+ }
|
|
|
} else {
|
|
|
- getOrderInfo(purchase.orderId)
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
+ callback?.onResult(-1, "消耗订单异常", consumeHandler)
|
|
|
+ disConnection()
|
|
|
}
|
|
|
}
|
|
|
- notifyOrder2Backend(activity, orderId, purchase, true)
|
|
|
}
|
|
|
|
|
|
-
|
|
|
private fun disConnection() {
|
|
|
- billingClient.apply {
|
|
|
+ billingClient?.apply {
|
|
|
if (isReady) {
|
|
|
Logger.d("断开谷歌收银台连接,以清空被消耗或者失败的缓存订单")
|
|
|
endConnection()
|
|
|
+ billingClient = null
|
|
|
+ callback = null
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private fun saveOrderInfo(googleOrderId: String, orderId: String) {
|
|
|
- try {
|
|
|
- MMKVHandler.instance.orderKV.encode(googleOrderId, orderId)
|
|
|
- } catch (e: JSONException) {
|
|
|
- e.printStackTrace()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private fun getOrderInfo(googleOrderId: String): String {
|
|
|
- val info = MMKVHandler.instance.orderKV.decodeString(googleOrderId)
|
|
|
- Logger.d("getOrderInfo : $info")
|
|
|
- return if (TextUtils.isEmpty(info)) {
|
|
|
- ""
|
|
|
- } else {
|
|
|
- info!!
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private fun removeOrderInfo(googleOrderId: String) {
|
|
|
- MMKVHandler.instance.orderKV.removeValueForKey(googleOrderId)
|
|
|
- }
|
|
|
-
|
|
|
private fun BillingResult.isOk(): Boolean {
|
|
|
return responseCode == BillingClient.BillingResponseCode.OK
|
|
|
}
|
|
@@ -311,7 +231,27 @@ import org.json.JSONObject
|
|
|
Logger.d("$callbackFuncName , code : $responseCode , msg : $debugMessage")
|
|
|
}
|
|
|
|
|
|
+ override fun onPurchasesUpdated(billingResult: BillingResult, list: MutableList<Purchase>?) {
|
|
|
+ //谷歌支付结果在这里回调
|
|
|
+ billingResult.log("onPurchasesUpdated")
|
|
|
+ if (billingResult.isOk()) {
|
|
|
+ if (list.isNullOrEmpty()) {
|
|
|
+ disConnection()
|
|
|
+ callback?.onResult(-1, "支付失败", consumeHandler)
|
|
|
+ } else {
|
|
|
+ val purchase = list[0]
|
|
|
+ val jsonObject = JSONObject()
|
|
|
+ jsonObject.put("order_id", purchase.accountIdentifiers?.obfuscatedAccountId)
|
|
|
+ jsonObject.put("order_notify_data", purchase.originalJson)
|
|
|
+ callback?.onResult(1, jsonObject.toString(), consumeHandler)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ callback?.onResult(-1, "支付失败", consumeHandler)
|
|
|
+ disConnection()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
interface InAppBillingCallback {
|
|
|
- fun onResult(code: Int, result: String)
|
|
|
+ fun onResult(code: Int, result: String, consumeHandler: IOrder)
|
|
|
}
|
|
|
}
|