集成Google Play支付

前言

這篇文章很早就想寫了,由於時間關係一直拖到現在,我相信這篇文章對大多數想要接入Goole Play支付的小夥伴來說,會少走許多坑的,在這裏說明一下,筆者在集成過程中踩了不少坑,所有請大家盡情享用成果,廢話不多說直接切入正題。

注意事項及準備工作

  • 創建一個非國內的Google賬號(這步很重要,國內賬號不支持支付)
  • 手機端開啓VPN,選擇Google賬號同一個國家的VPN,否則可能導致支付失敗
  • 手機端下載Google Play App並登錄
  • Google Play賬號綁定國外銀行或者購買禮品卡,用於支付(建議沒有國外銀行卡的小夥伴購買禮品卡來用於支付,不知道購買渠道的筆者可以幫忙,聯繫方式QQ:643614219)

開始集成

閱讀文檔

支付大致流程

  • 創建商品:使用 Google Play 管理中心配置應用內商品
  • APP端根據創建的商品Id,獲取商品詳情
  • 根據商品信息進行支付
  • 驗證支付結果

開始集成

引入倉庫

implementation 'com.android.billingclient:billing:2.1.0'

AndroidManifest.xml文件添加權限

<uses-permission android:name="com.android.vending.BILLING" />

與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() 中收到的其他購買詳情。
驗證購買交易分爲分爲兩種方式:

  • 在服務器上驗證購買交易

在這裏插入圖片描述

  • 在設備上驗證購買交易

詳情請點擊鏈接查看https://developer.android.com/google/play/billing/billing_library_overview
我這裏示例是到服務器去驗證,

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章