BillingClient - queryProductDetailsAsync 多次返回错误状态(2、6、12)

问题描述 投票:0回答:1

我在游戏中使用计费客户端,以便让人们在应用程序项目中购买。

根据我的日志,许多用户无法购买该商品,因为购买流程未启动。

日志显示,大多数启动购买流程的用户都会“卡在”queryProductDetailsAsync 方法上,从而导致错误:

int SERVICE_UNAVAILABLE = 2;
整数错误 = 6;
int NETWORK_ERROR = 12;

问题是,我在成功调用 startConnection 后使用 queryProductDetailsAsync - 我不明白为什么会出现网络/连接错误。

根据我的测试,它总是成功的。 我也在朋友的手机上测试了一下,也成功了。 此外,我确实看到一些用户成功购买。 所以我猜这不是配置问题。

所有故障都来自用户设备的日志

这是我的 BillingHelper 类的代码:

import android.app.Activity
import android.content.Context
import android.os.Handler
import android.os.Looper
import com.android.billingclient.api.*
import com.android.billingclient.api.BillingFlowParams.ProductDetailsParams
import java.lang.ref.WeakReference

class BillingHelper
{
    // region Enum

    enum class PurchaseStatus
    {
        PURCHASED,
        PENDING
    }

    // endregion

    // region Companion

    companion object
    {
        private const val TAG = "BillingHelper"
    }

    // endregion

    // region Listener

    interface BillingHelperListener
    {
        fun purchaseStatusUpdated(itemId: String, status: PurchaseStatus)
    }

    // endregion

    // region Properties

    private var billingClient: BillingClient? = null
    private var context: WeakReference<Context>? = null
    private var listener: BillingHelperListener? = null
    private val handler = Handler(Looper.getMainLooper())

    // endregion

    // region Init

    fun init(context: Context)
    {
        this.context = WeakReference(context)
    }

    fun setListener(listener: BillingHelperListener)
    {
        this.listener = listener
    }

    // endregion

    // region Purchase flow

    fun launchPurchase(activity: Activity, itemId: String, block: (purchaseStarted: Boolean) -> Unit)
    {
        KLog.i(TAG, "launchPurchase - $itemId")

        connectToBillingClient { connected ->

            KLog.i(TAG, "launchPurchase - $itemId. connected? - $connected")

            if (connected)
            {
                prepareSkuForPurchase(activity, itemId, block)
            } else
            {
                handler.post {

                    KLog.i(TAG, "launchPurchase - $itemId. invoking false")
                    block.invoke(false)
                }
            }
        }
    }

    private fun connectToBillingClient(block: (connected: Boolean) -> Unit)
    {
        KLog.i(TAG, "connectToBillingClient")

        getBillingClient()?.let {

            if (it.isReady)
            {
                KLog.i(TAG, "connectToBillingClient - already connected")
                block.invoke(true)
                return@let
            }

            it.startConnection(object : BillingClientStateListener
            {
                override fun onBillingSetupFinished(billingResult: BillingResult)
                {
                    KLog.i(TAG, "connectToBillingClient::onBillingSetupFinished")

                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK)
                    {
                        KLog.i(TAG, "connectToBillingClient::onBillingSetupFinished - connected")
                        block.invoke(true)
                        return
                    }

                    KLog.i(TAG, "connectToBillingClient::onBillingSetupFinished - invoking false")
                    block.invoke(false)
                }

                override fun onBillingServiceDisconnected()
                {
                    KLog.i(TAG, "connectToBillingClient::onBillingServiceDisconnected - invoking false")
                    block.invoke(false)
                }
            })
        }
    }

    private fun prepareSkuForPurchase(activity: Activity, itemID: String, block: (purchaseStarted: Boolean) -> Unit)
    {
        KLog.i(TAG, "prepareSkuForPurchase - $itemID")

        val skuList = ArrayList<String>()
        skuList.add(itemID)

        val productList =
            listOf(
                QueryProductDetailsParams.Product.newBuilder()
                    .setProductId(itemID)
                    .setProductType(BillingClient.ProductType.INAPP)
                    .build()
            )

        val params = QueryProductDetailsParams.newBuilder()
        params.setProductList(productList)

        getBillingClient()?.queryProductDetailsAsync(params.build()) { billingResult, skuDetailsList ->

            KLog.i(TAG, "prepareSkuForPurchase::queryProductDetailsAsync - billing result - $billingResult")

            /**
             * PROBLEM IS HERE - ACCORDING TO THE LOG - IT SAYS:
             *   1 - billing result - Response Code: ERROR, Debug Message: An internal error occurred.
             *   2 - billing result - Response Code: NETWORK_ERROR, Debug Message: An internal error occurred.
             *   3 - billing result - Response Code: SERVICE_UNAVAILABLE, Debug Message: Timeout communicating with service.
             */

            var purchaseStarted = false

            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList.isNotEmpty())
            {
                launchSkuPurchase(activity, skuDetailsList[0])
                purchaseStarted = true
            }

            handler.post {

                KLog.i(TAG, "prepareSkuForPurchase::queryProductDetailsAsync - invoking purchase started? - $purchaseStarted")
                block.invoke(purchaseStarted)
            }
        }
    }

    private fun launchSkuPurchase(activity: Activity, productDetails: ProductDetails)
    {
        KLog.i(TAG, "launchSkuPurchase - $productDetails")
        val params = ProductDetailsParams.newBuilder()
        params.setProductDetails(productDetails)
        val billingFlowParams = BillingFlowParams.newBuilder().setProductDetailsParamsList(listOf(params.build())).build()
        getBillingClient()?.launchBillingFlow(activity, billingFlowParams)
    }

    private fun handleSuccessPurchase(purchase: Purchase)
    {
        KLog.i(TAG, "handleSuccessPurchase - $purchase")
        KLog.i(TAG, "handleSuccessPurchase. state = - ${purchase.purchaseState}")

        if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED)
        {
            if (!purchase.isAcknowledged)
            {
                acknowledgePurchase(purchase)
            } else
            {
                handler.post {

                    listener?.purchaseStatusUpdated(purchase.products.firstOrNull() ?: "", PurchaseStatus.PURCHASED)
                }
            }
        } else if (purchase.purchaseState == Purchase.PurchaseState.PENDING)
        {
            handler.post {

                listener?.purchaseStatusUpdated(purchase.products.firstOrNull() ?: "", PurchaseStatus.PENDING)
            }
        }
    }

    private fun acknowledgePurchase(purchase: Purchase)
    {
        KLog.i(TAG, "acknowledgePurchase - $purchase")

        val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.purchaseToken).build()

        getBillingClient()?.acknowledgePurchase(acknowledgePurchaseParams) { result ->

            KLog.i(TAG, ":acknowledgePurchase::status - ${result.responseCode}")

            if (result.responseCode == BillingClient.BillingResponseCode.OK)
            {
                handler.post {

                    listener?.purchaseStatusUpdated(purchase.products.firstOrNull() ?: "", PurchaseStatus.PURCHASED)
                }
            }
        }
    }

    private val purchaseUpdateListener = PurchasesUpdatedListener { billingResult, purchases ->

        KLog.i(TAG, "purchaseUpdateListener::onPurchasesUpdated : $billingResult")

        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && !purchases.isNullOrEmpty())
        {
            val purchase = purchases.first()
            handleSuccessPurchase(purchase)
        }
    }

    // endregion

    // region Billing client

    private fun getBillingClient(): BillingClient?
    {
        val context = this.context?.get() ?: return let {

            KLog.i(TAG, "getBillingClient - context is null")
            null
        }

        var billingClient = this.billingClient

        if (billingClient == null)
        {
            KLog.i(TAG, "getBillingClient - creating new billing client")
            billingClient = BillingClient.newBuilder(context)
                .setListener(purchaseUpdateListener)
                .enablePendingPurchases()
                .build()

            this.billingClient = billingClient
        } else
        {
            KLog.i(TAG, "getBillingClient - using existing billing client")
        }

        return billingClient
    }

    // endregion
}

如您所见 - 问题出在 queryProductDetailsAsync 方法中。

我错过了什么?

我正在使用: 实现 'com.android.billingclient:billing:7.0.0'

android android-billing play-billing-library
1个回答
-2
投票

如果您是狂热的 Instagram 用户,您可能听说过 InstaUp APK。它是 Instagram 的修改和定制版本,提供一系列独特的功能。借助 InstaUp,您可以从 IGTV 和 Instagram 下载高清图像和视频、复制贴纸,甚至为您的帐户获得无限的真实关注者。 https://instaupak.com/

© www.soinside.com 2019 - 2024. All rights reserved.