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

Billing Library 1.0中Google Play未调用onPurchasesUpdated问题咨询

我来帮你把恢复Google Play购买项目的完整流程梳理清楚,结合你已经写的代码,把缺失的部分补全并解释关键要点:

恢复Google Play购买的完整实现步骤

首先,确保你的Activity/Fragment已经实现了PurchasesUpdatedListener接口——这是接收购买更新回调的前提。接下来是完整的代码实现:

class YourActivity : AppCompatActivity(), PurchasesUpdatedListener {
    private lateinit var mBillingClient: BillingClient

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 初始化BillingClient,注意别漏了enablePendingPurchases()
        mBillingClient = BillingClient.newBuilder(this)
            .setListener(this) // 绑定你实现的监听器
            .enablePendingPurchases() // 处理待完成的购买,2.0+版本必填
            .build()
        
        // 启动与Google Play Billing服务的连接
        mBillingClient.startConnection(object : BillingClientStateListener {
            override fun onBillingServiceDisconnected() {
                // 连接断开时的重试逻辑,避免服务中断后无法恢复
                retryBillingConnection()
            }

            override fun onBillingSetupFinished(result: BillingResult) {
                if (result.responseCode == BillingClient.BillingResponseCode.OK) {
                    // 连接成功,立即执行恢复购买操作
                    restorePurchases()
                } else {
                    // 连接失败,提示用户或做其他错误处理
                    Toast.makeText(this@YourActivity, "Billing服务连接失败: ${result.debugMessage}", Toast.LENGTH_SHORT).show()
                }
            }
        })
    }

    // 重试连接的辅助方法,加入延迟避免频繁请求
    private fun retryBillingConnection() {
        Handler(Looper.getMainLooper()).postDelayed({
            if (!mBillingClient.isReady) {
                mBillingClient.startConnection(this)
            }
        }, 3000)
    }

    // 核心:恢复购买的方法
    private fun restorePurchases() {
        // 恢复一次性内购(如果是订阅,换成BillingClient.SkuType.SUBS)
        mBillingClient.queryPurchasesAsync(BillingClient.SkuType.INAPP) { result, purchases ->
            if (result.responseCode == BillingClient.BillingResponseCode.OK && purchases.isNotEmpty()) {
                // 处理恢复到的所有购买项目
                handleRestoredPurchases(purchases)
            } else {
                // 没有可恢复的购买,或请求失败
                Toast.makeText(this@YourActivity, "暂无可恢复的购买项目", Toast.LENGTH_SHORT).show()
            }
        }
    }

    // 处理恢复到的购买项目
    private fun handleRestoredPurchases(purchases: List<Purchase>) {
        for (purchase in purchases) {
            if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                if (!purchase.isAcknowledged) {
                    // 未确认的购买必须调用acknowledgePurchase,否则Google会自动退款
                    val acknowledgeParams = AcknowledgePurchaseParams.newBuilder()
                        .setPurchaseToken(purchase.purchaseToken)
                        .build()
                    mBillingClient.acknowledgePurchase(acknowledgeParams) { ackResult ->
                        if (ackResult.responseCode == BillingClient.BillingResponseCode.OK) {
                            // 确认成功,给用户解锁对应功能
                            unlockPremiumFeatures()
                        }
                    }
                } else {
                    // 已确认的购买,直接解锁功能
                    unlockPremiumFeatures()
                }
            }
        }
    }

    // 实现PurchasesUpdatedListener的回调方法,处理新购买或购买更新
    override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList<Purchase>?) {
        when (result.responseCode) {
            BillingClient.BillingResponseCode.OK -> {
                purchases?.forEach { purchase ->
                    // 处理新完成的购买
                    handlePurchase(purchase)
                }
            }
            BillingClient.BillingResponseCode.USER_CANCELED -> {
                // 用户取消了购买流程
                Toast.makeText(this, "已取消购买", Toast.LENGTH_SHORT).show()
            }
            else -> {
                // 其他错误情况,比如服务不可用、权限不足等
                Toast.makeText(this, "购买失败: ${result.debugMessage}", Toast.LENGTH_SHORT).show()
            }
        }
    }

    // 处理新购买的逻辑(和恢复购买的确认逻辑一致)
    private fun handlePurchase(purchase: Purchase) {
        if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED && !purchase.isAcknowledged) {
            val acknowledgeParams = AcknowledgePurchaseParams.newBuilder()
                .setPurchaseToken(purchase.purchaseToken)
                .build()
            mBillingClient.acknowledgePurchase(acknowledgeParams) { ackResult ->
                if (ackResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    unlockPremiumFeatures()
                }
            }
        }
    }

    // 这里写解锁付费功能的具体逻辑,比如保存状态到本地
    private fun unlockPremiumFeatures() {
        Toast.makeText(this, "已解锁付费功能", Toast.LENGTH_SHORT).show()
        // 示例:保存到SharedPreferences
        getSharedPreferences("AppPrefs", MODE_PRIVATE)
            .edit()
            .putBoolean("isPremium", true)
            .apply()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 页面销毁时断开Billing连接,释放资源
        if (mBillingClient.isReady) {
            mBillingClient.endConnection()
        }
    }
}

关键注意事项

  • 必须调用enablePendingPurchases():从Play Billing Library 2.0版本开始,这个方法是强制要求的,用于处理用户发起购买但未完成(比如网络中断)的情况。
  • 区分商品类型:恢复购买时要根据你的商品是一次性内购(SkuType.INAPP)还是订阅(SkuType.SUBS)选择对应的方法。
  • 购买确认的必要性:所有已完成的购买都必须调用acknowledgePurchase进行确认,否则Google Play会在3天后自动退款给用户。
  • 连接重试逻辑:onBillingServiceDisconnected回调中一定要加入重试机制,保证服务断开后能重新建立连接,避免影响用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:17:04