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) { 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 { queryPurchasesAsync(BillingClient.SkuType.INAPP, object : PurchasesResponseListener { override fun onQueryPurchasesResponse(billingResult: BillingResult, list: MutableList) { 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() 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, _ -> logBillingResult("onConsumeResponse", billingResult) dismissDialog() if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) { // saveOrder2Local() if (isCache) { querySkuDetails(activity) } else { disConnection() implCallback.onResult(0, "支付成功") } removeOrderInfo(purchase.orderId) } else { disConnection() implCallback.onResult(-1, "消耗订单异常") 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() } } }