天天看点

集成Google Play支付

前言

这篇文章很早就想写了,由于时间关系一直拖到现在,我相信这篇文章对大多数想要接入Goole Play支付的小伙伴来说,会少走许多坑的,在这里说明一下,笔者在集成过程中踩了不少坑,所有请大家尽情享用成果,废话不多说直接切入正题。

注意事项及准备工作

  • 创建一个非国内的Google账号(这步很重要,国内账号不支持支付)
  • 手机端开启VPN,选择Google账号同一个国家的VPN,否则可能导致支付失败
  • 手机端下载Google Play App并登录
  • Google Play账号绑定国外银行或者购买礼品卡,用于支付(建议没有国外银行卡的小伙伴购买礼品卡来用于支付,不知道购买渠道的笔者可以帮忙,联系方式QQ:643614219)

开始集成

阅读文档

  • 建议大家在集成之前先通读一遍文档,这样有助于大家更高效的集成文档,官方文档地址:https://developer.android.com/google/play/billing/billing_library_overview

支付大致流程

  • 创建商品:使用 Google Play 管理中心配置应用内商品
  • APP端根据创建的商品Id,获取商品详情
  • 根据商品信息进行支付
  • 验证支付结果

开始集成

引入仓库

AndroidManifest.xml文件添加权限

与Google Play建立连接

billingClient?.startConnection(object : BillingClientStateListener {
     override fun onBillingSetupFinished(billingResult: BillingResult) {
            statusData.value = StatusInfo(ActionCode.TYPE_ACTION_LOADED)
            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                // The BillingClient is ready. You can query purchases here.
                LogPrinter.e("onBillingSetupFinished", "连接成功")
                //查询商品详情
                querySkuDetails(googleProductId)
            } else {
                LogPrinter.e(
                        "onBillingSetupFinished",
                        "连接失败了:responseCode ${billingResult.responseCode}"
                )
            }
        }

        override fun onBillingServiceDisconnected() {
                billingClient = null
                LogPrinter.e("onBillingDisconnected", "连接失败了")
        }
    })

           

查询商品信息

//查询应用内商品详情
    fun querySkuDetails(googleProductId: String) {
        val skuList = ArrayList<String>()
        skuList.add(googleProductId)
//        skuList.add("unlock_face")//商品id
        val params = SkuDetailsParams.newBuilder()
        params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
        billingClient?.querySkuDetailsAsync(
            params.build()
        ) { billingResult, skuDetailsList ->
            if (billingResult!!.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
                //查找商品详情
                for (skuDetailsItem in skuDetailsList) {
                    val sku = skuDetailsItem.sku
                    val price = skuDetailsItem.price
                    Log.e("skuDetails", "$sku $price")
                    if (googleProductId == sku) {
                        skuDetails = skuDetailsItem
                    }
                }
            } 
        }

    }

           

发起支付

private fun doGooPlayPay() {
        val flowParams = BillingFlowParams.newBuilder()
            .setSkuDetails(skuDetails)
            .build()
        billingClient?.launchBillingFlow(context, flowParams)
    }
           

支付成功后确认购买交易

如果您使用的是 Google Play 结算库版本 2.0 或更高版本,则必须在三天内确认所有购买交易。如果没能正确确认,将导致系统对相应购买交易按退款处理。

Google Play 支持从您的应用内部(应用内)或外部(应用外)购买商品。为了确保无论用户在哪里购买您的商品,Google Play 都能提供一致的购买体验,您必须在授予用户权利后尽快确认通过 Google Play 结算库收到的所有处于 SUCCESS 状态的购买交易。如果您在三天内未确认购买交易,则用户会自动收到退款,并且 Google Play 会撤消该购买交易。对于待处理的交易,该三天期限不包含购买交易处于 PENDING 状态的时间,而是从购买交易改为 SUCCESS 状态时算起。

您可以使用以下方法之一确认购买交易:

对于消耗型商品,请使用客户端 API 中的 consumeAsync()。

对于非消耗型商品,请使用客户端 API 中的 acknowledgePurchase()。

还可以使用服务器 API 中新增的 acknowledge() 方法。

对于消耗型商品,consumeAsync() 接受包含开发者载荷字段的 ConsumeParams 对象,如以下示例中所示:

val client: BillingClient = ...
fun consumePurchase() {
    val consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(/* token */)
            .setDeveloperPayload(/* payload */)
            .build()
    val consumeResult = withContext(Dispatchers.IO) {
        client.consumePurchase(consumeParams)
    }
}
           

下面是我代码里的示例

override fun onPurchasesUpdated(
        billingResult: BillingResult,
        purchases: MutableList<Purchase>?
    ) {
        statusData.value = StatusInfo(ActionCode.TYPE_ACTION_LOADED)
        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
            for (purchase in purchases) {
                if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                    if (!purchase.isAcknowledged) {//没有确认去确认
                        Log.e(
                            "去确认购买",
                            "${purchase.purchaseToken} ${purchase.developerPayload} ${purchase}"
                        )
                        consumePurchase(purchase)
                    } else {
                        Log.d("onPurchasesUpdated", "purchaseState 商品已经购买 $purchase")
                    }

                } else {
                    Log.d("onPurchasesUpdated", "purchaseState ${purchase.purchaseState}")
                }
            }
        } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
            // Handle an error caused by a user cancelling the purchase flow.
            statusData.value = StatusInfo(ActionCode.TYPE_ACTION_MESSAGE, "用户取消购买了")
        } else {
            // Handle any other error codes.
            statusData.value = StatusInfo(
                ActionCode.TYPE_ACTION_MESSAGE,
                "购买失败 responseCode:${billingResult.responseCode} Message:${billingResult.debugMessage} "
            )

        }

        Log.e(
            "onPurchasesUpdated",
            "购买结果 ${billingResult.responseCode} ${billingResult.debugMessage}  purchases $purchases"
        )
    }

    /**
     * 对于消耗型商品
     */
    private fun consumePurchase(purchase: Purchase) {
        statusData.value= StatusInfo(ActionCode.TYPE_ACTION_LOADING_DIALOG)
        val consumeParams =
            ConsumeParams.newBuilder()
                .setPurchaseToken(purchase.purchaseToken)
                .setDeveloperPayload(paymentCode)
                .build()
        billingClient?.consumeAsync(
            consumeParams
        ) { billingResult, p1 ->
            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                val body = GooglePayResultDto(
                    commonRepository.getUserInfo()!!.id
                    , purchase.orderId
                    , purchase.packageName
                    , paymentCode
                    , purchase.sku
                    , purchase.purchaseToken
                    , commonRepository.getUserInfo()!!.uuid
                )
                commonRepository.googlePayCall(body)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(object : BaseObserver<BaseResponse<Any>>() {
                        override fun onRequestStart() {
                        }

                        override fun onRequestEnd() {
                            statusData.value=StatusInfo(ActionCode.TYPE_ACTION_LOADED)
                        }

                        override fun onSuccessful(data: BaseResponse<Any>?) {
                            queryPayResult()
                        }

                        override fun onFailure(failureInfo: StatusInfo) {
                            queryPayResult()
                        }
                    })

            }
            Log.e(
                "consumePurchase",
                "responseCode:${billingResult.responseCode} ${billingResult.debugMessage}"
            )
        }
    }
           

验证购买交易

每次向用户提供他们所购买的商品的访问权限之前,您都应该验证购买交易是否处于 PURCHASED 状态,并验证应用在 onPurchasesUpdated() 中收到的其他购买详情。

验证购买交易分为分为两种方式:

  • 在服务器上验证购买交易

集成Google Play支付
  • 在设备上验证购买交易

详情请点击链接查看https://developer.android.com/google/play/billing/billing_library_overview

我这里示例是到服务器去验证,

继续阅读