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

Android订阅更新异常求助:切换失败与Billing v4崩溃问题

Google Play订阅升级/降级问题排查与修复方案

问题1:订阅切换后Play商店显示异常,重复购买出现双订阅

原因分析

  1. 订阅更新参数有效性不足:代码依赖本地缓存的旧订阅令牌发起更新,若令牌过期或无效,Google Play会直接忽略替换请求,转为创建新订阅;重复操作时未强制走更新流程,直接触发普通购买,导致双订阅共存。
  2. 未同步Play商店订阅状态:订阅更新完成后,旧订阅会被标记为取消(按设置的 prorate 模式),但代码未主动查询最新状态,本地缓存和商店实际状态不一致。

修复方案

  • 使用实时有效令牌发起更新:在构建更新参数前,先查询当前Play商店的有效订阅,确保使用最新的未过期令牌:
// 发起订阅更新前先获取有效旧订阅
billingClient!!.queryPurchasesAsync(BillingClient.SkuType.SUBS) { result, purchases ->
    if (result.responseCode == BillingClient.BillingResponseCode.OK && purchases.isNotEmpty()) {
        val validOldPurchase = purchases.firstOrNull { 
            it.purchaseState == Purchase.PurchaseState.PURCHASED 
        }
        validOldPurchase?.let {
            val updateParams = BillingFlowParams.SubscriptionUpdateParams.newBuilder()
                .setOldSkuPurchaseToken(it.purchaseToken)
                .setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.DEFERRED)
                .build()
            // 发起订阅更新流程
            billingClient!!.launchBillingFlow(requireActivity(), 
                BillingFlowParams.newBuilder()
                    .setSkuDetails(targetSkuDetails)
                    .setSubscriptionUpdateParams(updateParams)
                    .build()
            )
        }
    }
}
  • 强制切换场景走更新流程:当用户已订阅且切换套餐时,禁止触发普通购买逻辑,必须走订阅更新流程。

问题2:订阅更新时setSuccessfulScreen()触发崩溃

原因分析

  1. UI操作未在主线程执行:onPurchasesUpdated()回调运行在后台线程,直接操作View违反Android UI线程规则,引发RuntimeException。
  2. 空指针风险:使用!!强制解耦View对象,若订阅更新时Fragment/Activity已销毁或重建,View实例为空,触发空指针崩溃(报错信息截断但符合此场景特征)。

修复方案

  • 主线程执行UI操作:用requireActivity().runOnUiThread包裹UI逻辑:
private fun setSuccessfulScreen() {
    requireActivity().runOnUiThread {
        group?.visibility = View.GONE
        group2?.visibility = View.VISIBLE
        subscribeBtn?.visibility = View.GONE
        lottieAnimation?.playAnimation()
    }
}
  • 增加生命周期判断与安全调用:避免强制非空断言,先判断Fragment状态确保View可用:
private fun setSuccessfulScreen() {
    if (!isAdded) return
    requireActivity().runOnUiThread {
        group?.visibility = View.GONE
        group2?.visibility = View.VISIBLE
        subscribeBtn?.visibility = View.GONE
        lottieAnimation?.let {
            if (!it.isAnimating) it.playAnimation()
        }
    }
}

额外优化建议

  1. 完善错误处理:当前仅处理BillingResponseCode.OK场景,需补充用户取消购买、网络错误等分支,避免状态不一致。
  2. 同步订阅状态:App启动或进入订阅页面时,主动调用queryPurchasesAsync获取最新状态,更新本地缓存。
  3. 添加日志:在订阅更新关键节点记录日志,便于排查Play商店返回的错误码(如ITEM_ALREADY_OWNED)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 04:15:56