|
@@ -0,0 +1,344 @@
|
|
|
|
+package cn.yyxx.eyuangame.core.impl.iab
|
|
|
|
+
|
|
|
|
+import android.app.Activity
|
|
|
|
+import android.text.TextUtils
|
|
|
|
+import cn.yyxx.eyuangame.base.entity.SdkChargeInfo
|
|
|
|
+import cn.yyxx.eyuangame.base.utils.Logger
|
|
|
|
+import cn.yyxx.eyuangame.core.entity.ResultInfo
|
|
|
|
+import cn.yyxx.eyuangame.core.impl.SdkBridgeImpl
|
|
|
|
+import cn.yyxx.eyuangame.core.internal.IImplCallback
|
|
|
|
+import cn.yyxx.eyuangame.core.internal.IRequestCallback
|
|
|
|
+import cn.yyxx.eyuangame.core.network.SdkRequest
|
|
|
|
+import cn.yyxx.eyuangame.core.utils.MMKVUtils
|
|
|
|
+import cn.yyxx.support.ResUtils
|
|
|
|
+import cn.yyxx.support.hawkeye.ToastUtils
|
|
|
|
+import com.android.billingclient.api.*
|
|
|
|
+import org.json.JSONException
|
|
|
|
+import org.json.JSONObject
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @author #Suyghur.
|
|
|
|
+ * Created on 2021/06/28
|
|
|
|
+ */
|
|
|
|
+class ChargeImpl : InAppBilling() {
|
|
|
|
+
|
|
|
|
+ //初始化IAB收银台客户端
|
|
|
|
+ //连接谷歌商店
|
|
|
|
+ private lateinit var implCallback: IImplCallback
|
|
|
|
+ private lateinit var chargeInfo: SdkChargeInfo
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ fun charge(activity: Activity, chargeInfo: SdkChargeInfo, callback: IImplCallback) {
|
|
|
|
+ if (!checkGoogleApiAvailability(activity)) {
|
|
|
|
+ ToastUtils.toastInfo(activity, "Your phone or Google account does not support In-app Billing")
|
|
|
|
+ callback.onResult(-1, "谷歌iab支付服务不可用")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ this.implCallback = callback
|
|
|
|
+ this.chargeInfo = chargeInfo
|
|
|
|
+ showDialog(activity)
|
|
|
|
+
|
|
|
|
+// checkLocalNotifyFailedOrder(activity)
|
|
|
|
+ getOrderId(activity)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun chargePurchasesUpdated(activity: Activity, purchase: Purchase) {
|
|
|
|
+ Logger.d("chargePurchasesUpdated")
|
|
|
|
+ notifyOrder2Backend(activity, chargeInfo.orderId, purchase, false)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun preRewardPurchasesUpdated(activity: Activity, purchase: Purchase) {
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun queryRewardInfo(activity: Activity) {
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 查询未消耗订单
|
|
|
|
+ */
|
|
|
|
+ override fun queryChargeInfo(activity: Activity) {
|
|
|
|
+ billingClient?.apply {
|
|
|
|
+ val list = queryPurchases(BillingClient.SkuType.INAPP).purchasesList
|
|
|
|
+ if (list.isNullOrEmpty()) {
|
|
|
|
+ //正常发起支付流程
|
|
|
|
+ querySkuDetails(activity)
|
|
|
|
+ } else {
|
|
|
|
+ Logger.e("存在未消耗订单,发起补单流程,size : ${list.size}")
|
|
|
|
+ run breaking@{
|
|
|
|
+ if (list.size > 0) {
|
|
|
|
+ list.forEach { purchase ->
|
|
|
|
+ if (purchase.sku == SdkBridgeImpl.initBean.rewardId) {
|
|
|
|
+ Logger.e("存在阻塞的预注册奖励,停止支付流程")
|
|
|
|
+ if (list.size == 1) {
|
|
|
|
+ dismissDialog()
|
|
|
|
+ disConnection()
|
|
|
|
+ ToastUtils.toastInfo(activity, "In-app Billing has some error , please restart app and try again")
|
|
|
|
+ implCallback.onResult(-1, "存在阻塞的预注册奖励,停止支付流程")
|
|
|
|
+ }
|
|
|
|
+ //跳出支付流程
|
|
|
|
+ return@breaking
|
|
|
|
+ } else {
|
|
|
|
+ consumeCacheOrder(activity, purchase)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ //发起正常支付流程
|
|
|
|
+ querySkuDetails(activity)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// queryPurchasesAsync(BillingClient.SkuType.INAPP, object : PurchasesResponseListener {
|
|
|
|
+// override fun onQueryPurchasesResponse(billingResult: BillingResult, list: MutableList<Purchase>) {
|
|
|
|
+// logBillingResult("onQueryPurchasesResponse", billingResult)
|
|
|
|
+// if (list.isNullOrEmpty()) {
|
|
|
|
+// //正常发起支付流程
|
|
|
|
+// Logger.d("正常发起支付流程")
|
|
|
|
+// querySkuDetails(activity)
|
|
|
|
+// } else {
|
|
|
|
+// Logger.e("存在未消耗订单,发起补单流程,size : ${list.size}")
|
|
|
|
+// run breaking@{
|
|
|
|
+// list.forEach { purchase ->
|
|
|
|
+// purchase.skus.forEach {
|
|
|
|
+// if (it.equals(SdkBridgeImpl.initBean.rewardId)) {
|
|
|
|
+// Logger.e("存在阻塞的预注册奖励,停止支付流程")
|
|
|
|
+// if (list.size == 1) {
|
|
|
|
+// dismissDialog()
|
|
|
|
+// disConnection()
|
|
|
|
+// ToastUtils.toastInfo(activity, "In-app Billing has some error , please restart app and try again")
|
|
|
|
+// implCallback.onResult(-1, "存在阻塞的预注册奖励,停止支付流程")
|
|
|
|
+// }
|
|
|
|
+// //跳出支付流程
|
|
|
|
+// return@breaking
|
|
|
|
+// } else {
|
|
|
|
+// consumeCacheOrder(activity, purchase)
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun purchasesUpdatedFailed() {
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun connectGooglePlayFailed() {
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 检查本地通知发货失败订单
|
|
|
|
+ */
|
|
|
|
+ private fun checkLocalNotifyFailedOrder(activity: Activity) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取订单号
|
|
|
|
+ */
|
|
|
|
+ private fun getOrderId(activity: Activity) {
|
|
|
|
+ SdkRequest.instance.createOrder(activity, chargeInfo, object : IRequestCallback {
|
|
|
|
+ override fun onResponse(resultInfo: ResultInfo) {
|
|
|
|
+ if (resultInfo.code == 1 && !TextUtils.isEmpty(resultInfo.data)) {
|
|
|
|
+ try {
|
|
|
|
+ val jsonObject = JSONObject(resultInfo.data)
|
|
|
|
+ chargeInfo.orderId = jsonObject.getString("order_id")
|
|
|
|
+ Logger.d("order_id ---> ${chargeInfo.orderId}")
|
|
|
|
+ //获取订单号成功,初始化IAB收银台客户端
|
|
|
|
+ Logger.d("获取订单号成功,初始化IAB收银台客户端")
|
|
|
|
+ initializeBillingClient(activity)
|
|
|
|
+ connectGooglePlay(activity, false)
|
|
|
|
+ } catch (e: JSONException) {
|
|
|
|
+ e.printStackTrace()
|
|
|
|
+ dismissDialog()
|
|
|
|
+ val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
|
|
|
|
+ ResUtils.getResString(activity, "yyxx_charge_tv_error")
|
|
|
|
+ } else {
|
|
|
|
+ resultInfo.msg
|
|
|
|
+ }
|
|
|
|
+ ToastUtils.toastInfo(activity, msg)
|
|
|
|
+ implCallback.onResult(-1, "获取订单异常")
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ dismissDialog()
|
|
|
|
+ val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
|
|
|
|
+ ResUtils.getResString(activity, "yyxx_charge_tv_error")
|
|
|
|
+ } else {
|
|
|
|
+ resultInfo.msg
|
|
|
|
+ }
|
|
|
|
+ ToastUtils.toastInfo(activity, msg)
|
|
|
|
+ implCallback.onResult(-1, "获取订单异常")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 查询商品信息
|
|
|
|
+ */
|
|
|
|
+ private fun querySkuDetails(activity: Activity) {
|
|
|
|
+ val skus = mutableListOf<String>()
|
|
|
|
+ skus.add(chargeInfo.productId)
|
|
|
|
+ val params = SkuDetailsParams.newBuilder().setType(BillingClient.SkuType.INAPP).setSkusList(skus).build()
|
|
|
|
+ billingClient?.querySkuDetailsAsync(params) { billingResult, list ->
|
|
|
|
+ logBillingResult("onSkuDetailsResponse", billingResult)
|
|
|
|
+ dismissDialog()
|
|
|
|
+ if (list.isNullOrEmpty()) {
|
|
|
|
+ //查询商品信息失败
|
|
|
|
+ Logger.e("查询商品信息失败")
|
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
|
+ implCallback.onResult(-1, "查询商品信息失败")
|
|
|
|
+ disConnection()
|
|
|
|
+ } else {
|
|
|
|
+ if (list.size == 1) {
|
|
|
|
+ val skuDetails = list[0]
|
|
|
|
+ Logger.d("product id : ${skuDetails.sku}")
|
|
|
|
+ launchBillingFlow(activity, skuDetails)
|
|
|
|
+ } else {
|
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
|
+ implCallback.onResult(-1, "查询商品信息异常")
|
|
|
|
+ disConnection()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 启动收银台
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+ private fun launchBillingFlow(activity: Activity, skuDetails: SkuDetails) {
|
|
|
|
+ billingClient?.apply {
|
|
|
|
+ if (isReady) {
|
|
|
|
+ val flowParams = BillingFlowParams.newBuilder().setObfuscatedAccountId(chargeInfo.orderId).setSkuDetails(skuDetails).build()
|
|
|
|
+
|
|
|
|
+ val billingResult = launchBillingFlow(activity, flowParams)
|
|
|
|
+ logBillingResult("launchBillingFlow", billingResult)
|
|
|
|
+ if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) {
|
|
|
|
+ dismissDialog()
|
|
|
|
+ disConnection()
|
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
|
+ implCallback.onResult(-1, "启动谷歌收银台失败")
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ dismissDialog()
|
|
|
|
+ disConnection()
|
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
|
+ implCallback.onResult(-1, "启动谷歌收银台失败")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 通知服务端发货
|
|
|
|
+ */
|
|
|
|
+ private fun notifyOrder2Backend(activity: Activity, orderId: String, purchase: Purchase, isCache: Boolean = false) {
|
|
|
|
+ SdkRequest.instance.notifyOrder(activity, orderId, purchase.originalJson, object : IRequestCallback {
|
|
|
|
+ override fun onResponse(resultInfo: ResultInfo) {
|
|
|
|
+ if (resultInfo.code == 1) {
|
|
|
|
+ //消耗订单
|
|
|
|
+ consumeAsync(activity, purchase, isCache)
|
|
|
|
+ } else {
|
|
|
|
+ //失败则缓存订单
|
|
|
|
+ saveOrderInfo(purchase.orderId, orderId)
|
|
|
|
+ dismissDialog()
|
|
|
|
+ disConnection()
|
|
|
|
+ val msg = if (TextUtils.isEmpty(resultInfo.msg)) {
|
|
|
|
+ ResUtils.getResString(activity, "yyxx_charge_tv_error")
|
|
|
|
+ } else {
|
|
|
|
+ resultInfo.msg
|
|
|
|
+ }
|
|
|
|
+ ToastUtils.toastInfo(activity, msg)
|
|
|
|
+ implCallback.onResult(-1, "发货失败")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 消耗缓存订单
|
|
|
|
+ */
|
|
|
|
+ private fun consumeCacheOrder(activity: Activity, purchase: Purchase) {
|
|
|
|
+ //消耗完了再发起支付
|
|
|
|
+ Logger.d("消耗缓存订单 : $purchase")
|
|
|
|
+ var orderId = ""
|
|
|
|
+ purchase.accountIdentifiers?.apply {
|
|
|
|
+ orderId = if (!TextUtils.isEmpty(obfuscatedAccountId)) {
|
|
|
|
+ obfuscatedAccountId!!
|
|
|
|
+ } else {
|
|
|
|
+ //TODO getLocalOrderId
|
|
|
|
+ getOrderInfo(purchase.orderId)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ notifyOrder2Backend(activity, orderId, purchase, true)
|
|
|
|
+// consumeAsync(activity, purchase.purchaseToken, true)
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 消耗订单
|
|
|
|
+ */
|
|
|
|
+ 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, token ->
|
|
|
|
+ logBillingResult("onConsumeResponse", billingResult)
|
|
|
|
+ dismissDialog()
|
|
|
|
+ if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
|
|
|
+ // saveOrder2Local()
|
|
|
|
+ if (isCache) {
|
|
|
|
+ querySkuDetails(activity)
|
|
|
|
+ } else {
|
|
|
|
+ implCallback.onResult(0, "支付成功")
|
|
|
|
+ disConnection()
|
|
|
|
+ }
|
|
|
|
+ removeOrderInfo(purchase.orderId)
|
|
|
|
+ } else {
|
|
|
|
+ implCallback.onResult(-1, "消耗订单异常")
|
|
|
|
+ disConnection()
|
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ dismissDialog()
|
|
|
|
+ disConnection()
|
|
|
|
+ implCallback.onResult(-1, "消耗订单异常")
|
|
|
|
+ ToastUtils.toastInfo(activity, ResUtils.getResString(activity, "yyxx_charge_tv_error"))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun saveOrderInfo(googleOrderId: String, orderId: String) {
|
|
|
|
+ try {
|
|
|
|
+ MMKVUtils.instance.orderKV.encode(googleOrderId, orderId)
|
|
|
|
+ } catch (e: JSONException) {
|
|
|
|
+ e.printStackTrace()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun getOrderInfo(googleOrderId: String): String {
|
|
|
|
+ val info = MMKVUtils.instance.orderKV.decodeString(googleOrderId)
|
|
|
|
+ Logger.d("getOrderInfo : $info")
|
|
|
|
+ return if (TextUtils.isEmpty(info)) {
|
|
|
|
+ ""
|
|
|
|
+ } else {
|
|
|
|
+ info!!
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun removeOrderInfo(googleOrderId: String) {
|
|
|
|
+ MMKVUtils.instance.orderKV.removeValueForKey(googleOrderId)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ companion object {
|
|
|
|
+ val instance: ChargeImpl by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
|
|
|
+ ChargeImpl()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|