Google Play 结算服务超时

发布于 2025-01-15 05:00:06 字数 4663 浏览 3 评论 0原文

昨天,我在应用程序中为应用内购买设置了 Google Play 结算,一切都按预期运行,我可以查询产品、选择产品并购买。

今天这已经改变了,它突然不起作用并返回这些错误消息:

W/BillingClient: Async task is taking too long, cancel it!
D/billingSetupError: Timeout communicating with service

返回的错误响应代码是-3。下面是我用于连接到服务并查询 sku 详细信息的代码(所有内容都在我的视图模型中,因为我使用完整的撰写应用程序,因此无法访问我所在的活动或片段)

@HiltViewModel
class StoreViewModel @Inject constructor(
private val billingClientBuilder: BillingClient.Builder
) : ViewModel(), StoreEvents, BillingClientStateListener, PurchasesUpdatedListener {

companion object {
    const val TAG = "StoreViewModel"
}

private val _state = MutableStateFlow(StoreScreenState.default)
val state: StateFlow<StoreScreenState> = _state

private val _purchaseTokens = MutableStateFlow(emptyList<String?>())
val purchaseTokens: StateFlow<List<String?>> = _purchaseTokens

private val availableSkus = listOf(
    "comic_pack",
    "elements_pack"
)

private val BACKOFF_IN_MILLIS = 500
private var backoffAttempts = 0

private var billingClient = billingClientBuilder
    .setListener(this)
    .enablePendingPurchases()
    .build()

init {

    billingClient.startConnection(this)

    viewModelScope.launch {

        state.collect {
            it.skuDetails.forEach {
                Log.d(TAG, it.toString())
            }

        }
    }
}

private suspend fun queryOneTimeProducts(): List<SkuDetails> = withContext(Dispatchers.IO) {
    if (!billingClient.isReady) {
        Log.e("TAG", "queryOneTimeProducts: BillingClient is not ready")
        return@withContext emptyList()
    }

    val availableSkus = SkuDetailsParams
        .newBuilder()
        .setSkusList(availableSkus)
        .setType(BillingClient.SkuType.INAPP)
        .build()


    return@withContext runCatching {
        val result = billingClient.querySkuDetails(availableSkus)
        result.skuDetailsList ?: emptyList()
    }.getOrNull() ?: emptyList()
}

private suspend fun handlePurchase(purchase: Purchase) {

    Log.d("purchaseComplete", purchase.toString())

    val consumeParams = ConsumeParams.newBuilder()
        .setPurchaseToken(purchase.purchaseToken)
        .build()

    withContext(Dispatchers.IO) {
        billingClient.consumePurchase(consumeParams)
    }

}

private fun updateLoading(isLoading: Boolean) {
    _state.value = state.value.copy(
        loading = isLoading
    )
}

private fun updateProducts(products: List<SkuDetails>) {
    _state.value = state.value.copy(
        skuDetails = products
    )
}

override fun StoreItemClicked(activity: Activity, name: String) {

    val selectedSku = state.value.skuDetails.find { it.title == name }

    val flowParams = selectedSku?.let {
        it
        BillingFlowParams.newBuilder()
            .setSkuDetails(it)
            .build()
    }

    flowParams?.let { billingClient.launchBillingFlow(activity, it) }
}


override fun onBillingServiceDisconnected() {
    viewModelScope.launch {
        if (backoffAttempts == 0) {
            delay(BACKOFF_IN_MILLIS.toLong())
        } else {
            delay(backoffAttempts * BACKOFF_IN_MILLIS.toLong())
        }

        if (!billingClient.isReady) {
            billingClient.startConnection(this@StoreViewModel)
            backoffAttempts++
        }
    }
}

override fun onBillingSetupFinished(billingResult: BillingResult) {
    backoffAttempts = 0

    Log.d("responsecode", billingResult.responseCode.toString())

    if (billingResult.responseCode != 0) {

        if (billingResult.responseCode == 2 || billingResult.responseCode == 3) {

            viewModelScope.launch {

                Log.d("billingSetupError", billingResult.debugMessage)

            }
        } else {
            viewModelScope.launch {

                Log.d("billingSetupError", billingResult.debugMessage)

            }
        }

    } else {

        viewModelScope.launch {

            val products = queryOneTimeProducts()

            Log.d("PRODUCTS", products.toString())

            updateProducts(products)
            updateLoading(false)
        }
    }
}

override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList<Purchase>?) {
    if (result.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
        for (purchase in purchases) {
            viewModelScope.launch {
                Log.d("purchase", purchase.toString())
                handlePurchase(purchase)
            }
        }
    } else if (result.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {

    } else {
        // Handle any other error codes.
    }
}

}

I set up Google Play billing for in app purchases in my app yesterday, everything was working as expected and I could query the products, select them and purchase.

Today this has changed, it suddenly does not work and is returning these error messages:

W/BillingClient: Async task is taking too long, cancel it!
D/billingSetupError: Timeout communicating with service

The error response code coming back is -3. Below is my code for connecting to the service and querying the sku details (everything is in my viewmodel as im using a full compose app so no access to activity or fragments where i am)

@HiltViewModel
class StoreViewModel @Inject constructor(
private val billingClientBuilder: BillingClient.Builder
) : ViewModel(), StoreEvents, BillingClientStateListener, PurchasesUpdatedListener {

companion object {
    const val TAG = "StoreViewModel"
}

private val _state = MutableStateFlow(StoreScreenState.default)
val state: StateFlow<StoreScreenState> = _state

private val _purchaseTokens = MutableStateFlow(emptyList<String?>())
val purchaseTokens: StateFlow<List<String?>> = _purchaseTokens

private val availableSkus = listOf(
    "comic_pack",
    "elements_pack"
)

private val BACKOFF_IN_MILLIS = 500
private var backoffAttempts = 0

private var billingClient = billingClientBuilder
    .setListener(this)
    .enablePendingPurchases()
    .build()

init {

    billingClient.startConnection(this)

    viewModelScope.launch {

        state.collect {
            it.skuDetails.forEach {
                Log.d(TAG, it.toString())
            }

        }
    }
}

private suspend fun queryOneTimeProducts(): List<SkuDetails> = withContext(Dispatchers.IO) {
    if (!billingClient.isReady) {
        Log.e("TAG", "queryOneTimeProducts: BillingClient is not ready")
        return@withContext emptyList()
    }

    val availableSkus = SkuDetailsParams
        .newBuilder()
        .setSkusList(availableSkus)
        .setType(BillingClient.SkuType.INAPP)
        .build()


    return@withContext runCatching {
        val result = billingClient.querySkuDetails(availableSkus)
        result.skuDetailsList ?: emptyList()
    }.getOrNull() ?: emptyList()
}

private suspend fun handlePurchase(purchase: Purchase) {

    Log.d("purchaseComplete", purchase.toString())

    val consumeParams = ConsumeParams.newBuilder()
        .setPurchaseToken(purchase.purchaseToken)
        .build()

    withContext(Dispatchers.IO) {
        billingClient.consumePurchase(consumeParams)
    }

}

private fun updateLoading(isLoading: Boolean) {
    _state.value = state.value.copy(
        loading = isLoading
    )
}

private fun updateProducts(products: List<SkuDetails>) {
    _state.value = state.value.copy(
        skuDetails = products
    )
}

override fun StoreItemClicked(activity: Activity, name: String) {

    val selectedSku = state.value.skuDetails.find { it.title == name }

    val flowParams = selectedSku?.let {
        it
        BillingFlowParams.newBuilder()
            .setSkuDetails(it)
            .build()
    }

    flowParams?.let { billingClient.launchBillingFlow(activity, it) }
}


override fun onBillingServiceDisconnected() {
    viewModelScope.launch {
        if (backoffAttempts == 0) {
            delay(BACKOFF_IN_MILLIS.toLong())
        } else {
            delay(backoffAttempts * BACKOFF_IN_MILLIS.toLong())
        }

        if (!billingClient.isReady) {
            billingClient.startConnection(this@StoreViewModel)
            backoffAttempts++
        }
    }
}

override fun onBillingSetupFinished(billingResult: BillingResult) {
    backoffAttempts = 0

    Log.d("responsecode", billingResult.responseCode.toString())

    if (billingResult.responseCode != 0) {

        if (billingResult.responseCode == 2 || billingResult.responseCode == 3) {

            viewModelScope.launch {

                Log.d("billingSetupError", billingResult.debugMessage)

            }
        } else {
            viewModelScope.launch {

                Log.d("billingSetupError", billingResult.debugMessage)

            }
        }

    } else {

        viewModelScope.launch {

            val products = queryOneTimeProducts()

            Log.d("PRODUCTS", products.toString())

            updateProducts(products)
            updateLoading(false)
        }
    }
}

override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList<Purchase>?) {
    if (result.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
        for (purchase in purchases) {
            viewModelScope.launch {
                Log.d("purchase", purchase.toString())
                handlePurchase(purchase)
            }
        }
    } else if (result.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {

    } else {
        // Handle any other error codes.
    }
}

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

爱你是孤单的心事 2025-01-22 05:00:07

我在使用 v4.1.0 时遇到了同样的问题。
我改用了 3.0.2 版本,问题就消失了。
这可能是一个临时解决方案,因为不建议使用以前的版本。

也许 3.0.2 和 4.1.0 之间的版本也可以修复它。
在此处的发行说明中 https://developer.android.com/google/play /billing/release-notes 没有找到任何与“超时问题”相关的内容。

I have the same issue when using the v4.1.0.
I used the version 3.0.2 instead and the issue is gone.
This could be a temp solution, since it's not recommended to use a previous version.

Maybe a version between 3.0.2 and 4.1.0 could fix it as well.
In the release notes here https://developer.android.com/google/play/billing/release-notes didn't find anything related to the "timeout issue".

好多鱼好多余 2025-01-22 05:00:07

从版本 3.0.2 更新到 5.0.0 后遇到了同样的问题。当我在应用程序根本没有订阅的情况下查询订阅时,似乎会发生超时。

我的建议是跳过对没有任何配置产品的产品类型的查询,即当应用没有应用内商品时不要查询应用内商品,当应用程序没有应用内商品时不要查询订阅。应用程序没有订阅。

Had the same problem after the update from version 3.0.2 to 5.0.0. Seems that the timeout occurs when I query for subscriptions when the app has no subscriptions at all.

My advice is to skip the query for product types that don't have any configured products, i.e. don't query for in-app products when the app doesn't have in-app products, and don't query for subscriptions when the app doesn't have subscriptions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文