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

Android应用内更新陷入无限循环问题排查

应用内更新(In-app Update)无限安装循环问题排查

我正在实现应用内更新功能,但测试时遇到无限安装的问题:安装过程始终无法完成,按下返回键回到应用主界面后,更新界面会立即再次弹出并进入无限安装状态;即使重启应用(包括强制停止)、清除数据和缓存,问题依然存在,更新弹窗会反复出现。

问题截图

核心实现代码

class InAppUpdateTestHelper(
    private val activity: Activity,
    lifecycleOwner: LifecycleOwner,
    private val startUpdateFlowForResult: ActivityResultLauncher<IntentSenderRequest>,
) {
    private val appUpdateManager by lazy { AppUpdateManagerFactory.create(activity) }

    init {
        try {
            val defaultLifecycleObserver = object : DefaultLifecycleObserver {
                override fun onResume(owner: LifecycleOwner) {
                    checkIfAppUpdateInProgress()
                }
            }
            lifecycleOwner.lifecycle.addObserver(defaultLifecycleObserver)
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        forceUpdate()
    }

    private fun forceUpdate() {
        try {
            appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
                try {
                    val updateAvailable =
                        appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE

                    val isUpdateImmediateAllowed =
                        appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)

                    if (updateAvailable && isUpdateImmediateAllowed) {
                        appUpdateManager.startUpdateFlowForResult(
                            appUpdateInfo,
                            // an activity result launcher registered via registerForActivityResult
                            startUpdateFlowForResult,
                            AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE)
                                .build()
                        )
                    }
                } catch (e: Throwable) {
                    e.printStackTrace()
                }
            }.addOnFailureListener {
                Timber.e("appUpdateInfo addOnFailureListener ${it.message}")
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
    }

    private fun checkIfAppUpdateInProgress() {
        val startUpdateFlowForResult = startUpdateFlowForResult ?: return
        try {
            appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
                if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
                    try {
                        appUpdateManager.startUpdateFlowForResult(
                            appUpdateInfo,
                            // an activity result launcher registered via registerForActivityResult
                            startUpdateFlowForResult,
                            AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE)
                                .build()
                        )
                    } catch (e: Throwable) {
                        e.printStackTrace()
                    }
                }
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
    }
}

Activity初始化代码

private val startUpdateFlowForResult =
    registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
        // handle callback
        if (DEBUG) {
            val resultCode = result.resultCode
            Timber.d("startUpdateFlowForResult $resultCode")
        }
    }

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    inAppUpdateTestHelper = InAppUpdateTestHelper(
        activity = this,
        lifecycleOwner = this,
        startUpdateFlowForResult = startUpdateFlowForResult,
    )
}

更新信息

  • 问题出现在三星S22(Android 14)设备上,三星S10(Android 12)测试正常
  • 清除三星S22上Google Play的数据和缓存后,问题仍未解决
  • 计划在Android 14的Pixel模拟器上进一步测试

问题原因及修复方案

1. 核心问题

当用户取消更新返回应用时,Play Core未正确重置DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS状态,加上初始化时直接调用forceUpdate()、onResume中重复检查触发更新,形成了循环。

2. 具体修复步骤

(1)避免初始化时立即触发更新

移除init中的forceUpdate(),改为外部在合适时机调用,并添加触发条件:

// 修改InAppUpdateTestHelper的init和新增方法
init {
    try {
        val defaultLifecycleObserver = object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                checkIfAppUpdateInProgress()
            }
        }
        lifecycleOwner.lifecycle.addObserver(defaultLifecycleObserver)
    } catch (e: Throwable) {
        e.printStackTrace()
    }
}

fun checkAndStartUpdate() {
    forceUpdate()
}

Activity中仅首次创建时触发:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    inAppUpdateTestHelper = InAppUpdateTestHelper(
        activity = this,
        lifecycleOwner = this,
        startUpdateFlowForResult = startUpdateFlowForResult,
    )
    // 仅Activity首次创建时检查更新
    if (savedInstanceState == null) {
        inAppUpdateTestHelper.checkAndStartUpdate()
    }
}

(2)处理回调结果,主动重置状态

在更新回调中处理取消/失败场景,调用completeUpdate()终止更新流程:

private val startUpdateFlowForResult =
    registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
        when(result.resultCode) {
            Activity.RESULT_CANCELED,
            Activity.RESULT_FIRST_USER -> {
                // 用户取消或更新失败,重置状态
                appUpdateManager.appUpdateInfo.addOnSuccessListener { info ->
                    if (info.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
                        appUpdateManager.completeUpdate()
                    }
                }
            }
        }
        if (DEBUG) {
            Timber.d("startUpdateFlowForResult ${result.resultCode}")
        }
    }

(3)适配Android 14

确保使用最新版本的Play Core库(至少com.google.android.play:core:1.10.3),并更新设备上的Google Play服务。

(4)添加频率限制

用SharedPreferences记录检查时间,避免短时间内重复触发:

private fun shouldCheckUpdate(): Boolean {
    val sp = activity.getSharedPreferences("update_prefs", Context.MODE_PRIVATE)
    val lastCheck = sp.getLong("last_update_check", 0)
    val interval = 3600 * 1000 // 1小时间隔
    if (System.currentTimeMillis() - lastCheck > interval) {
        sp.edit().putLong("last_update_check", System.currentTimeMillis()).apply()
        return true
    }
    return false
}

// 修改checkAndStartUpdate
fun checkAndStartUpdate() {
    if (shouldCheckUpdate()) {
        forceUpdate()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:24:54