You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Google In-app-purchases v6无服务器环境下恢复购买失败求助

Google Play Billing v6+ 无服务器环境下恢复已购非消耗品解决方案

以下是针对重装/跨设备无法恢复非消耗品购买问题的具体客户端实现方案(无服务器依赖):

  • 确保BillingClient连接稳定并正确初始化
    查询返回空常因BillingClient未完全建立连接或断开后未重连导致。必须在onBillingSetupFinished确认连接成功后执行查询,同时监听断开事件自动重连:

    private lateinit var billingClient: BillingClient
    
    fun initBillingClient(context: Context) {
        billingClient = BillingClient.newBuilder(context)
            .enablePendingPurchases() // 必须开启,否则无法处理待购买状态
            .setListener { billingResult, purchases ->
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
                    handlePurchases(purchases)
                }
            }
            .build()
    
        connectBillingClient()
    }
    
    private fun connectBillingClient() {
        if (!billingClient.isReady) {
            billingClient.startConnection(object : BillingClientStateListener {
                override fun onBillingSetupFinished(billingResult: BillingResult) {
                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                        queryPurchases()
                    }
                }
    
                override fun onBillingServiceDisconnected() {
                    Handler(Looper.getMainLooper()).postDelayed({
                        connectBillingClient()
                    }, 1000)
                }
            })
        }
    }
    
  • 使用正确参数调用queryPurchasesAsync
    非消耗品属于INAPP类型,需确保查询参数指定正确类型,且完整处理回调结果:

    private fun queryPurchases() {
        val queryParams = QueryPurchasesParams.newBuilder()
            .setProductType(BillingClient.ProductType.INAPP)
            .build()
    
        billingClient.queryPurchasesAsync(queryParams) { billingResult, purchases ->
            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                if (purchases.isNotEmpty()) {
                    handlePurchases(purchases)
                } else {
                    // 首次查询为空,触发后台同步
                    triggerPurchaseSync()
                }
            }
        }
    }
    
  • 触发Google Play后台同步(无需用户额外操作)
    首次查询为空时,可发起目标非消耗品的静默购买请求(不会弹出付费弹窗,但会触发后台同步购买记录):

    private fun triggerPurchaseSync() {
        val productDetailsParams = QueryProductDetailsParams.newBuilder()
            .setProductList(listOf(
                QueryProductDetailsParams.Product.newBuilder()
                    .setProductId("你的非消耗品ID")
                    .setProductType(BillingClient.ProductType.INAPP)
                    .build()
            ))
            .build()
    
        billingClient.queryProductDetailsAsync(productDetailsParams) { billingResult, productDetailsList ->
            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && productDetailsList.isNotEmpty()) {
                val productDetails = productDetailsList[0]
                val billingFlowParams = BillingFlowParams.newBuilder()
                    .setProductDetailsParamsList(listOf(
                        BillingFlowParams.ProductDetailsParams.newBuilder()
                            .setProductDetails(productDetails)
                            .build()
                    ))
                    .build()
    
                val result = billingClient.launchBillingFlow(activity, billingFlowParams)
                if (result.responseCode == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
                    queryPurchases()
                }
            }
        }
    }
    
  • 处理待处理购买状态
    部分场景下购买可能处于待处理状态,需在回调中主动确认并处理:

    private fun handlePurchases(purchases: List<Purchase>) {
        for (purchase in purchases) {
            if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                if (!purchase.isAcknowledged) {
                    val acknowledgeParams = AcknowledgePurchaseParams.newBuilder()
                        .setPurchaseToken(purchase.purchaseToken)
                        .build()
                    billingClient.acknowledgePurchase(acknowledgeParams) { billingResult ->
                        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                            markItemAsOwned(purchase.products[0])
                        }
                    }
                } else {
                    markItemAsOwned(purchase.products[0])
                }
            } else if (purchase.purchaseState == Purchase.PurchaseState.PENDING) {
                // 提示用户等待或稍后重试
            }
        }
    }
    
  • 关键注意事项

    • 应用包名、签名需与Google Play控制台注册信息完全一致,否则无法获取购买记录
    • 测试需使用正式签名APK或Google Play内部测试渠道包,debug签名包可能无法正常跨设备查询
    • 避免应用启动时立即查询,等待Google账号完全登录后再发起(可监听账号登录状态变化)

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 20:12:41