如何在Google Play有新版本时实现Android应用后台更新
嘿,这个问题我刚好在几个项目里实践过,下面给你拆解几种可行的实现思路,从官方推荐的方案到自定义实现都覆盖到,帮你搞定后台自动更新的需求:
这是最省心也最符合Google政策的方案,毕竟Google Play本身就有完善的更新体系,咱们只需要借助Play Core Library来触发更新流程:
集成Play Core Library
在app的build.gradle里添加依赖:implementation 'com.google.android.play:app-update:2.1.0'选择合适的更新类型
Google提供了两种更新模式,其中Flexible Update更适合后台自动更新的场景:- Flexible Update:可以在后台静默下载APK,下载完成后再提示用户安装(也可以通过代码触发安装,但注意Android 8.0+需要用户确认安装,无法完全静默)
- Immediate Update:会强制弹出更新弹窗,用户必须更新才能继续使用,不太适合后台自动的需求
实现后台下载逻辑
咱们可以用AppUpdateManager来检查更新,然后启动后台下载:val appUpdateManager = AppUpdateManagerFactory.create(context) val appUpdateInfoTask = appUpdateManager.appUpdateInfo appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> // 检查是否有可用更新,且支持Flexible模式 if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) { // 启动后台下载 appUpdateManager.startUpdateFlowForResult( appUpdateInfo, AppUpdateType.FLEXIBLE, activity, REQUEST_CODE_UPDATE ) } }下载完成后,还可以监听下载状态,然后触发安装:
appUpdateManager.registerListener { state -> if (state.installStatus() == InstallStatus.DOWNLOADED) { // 提示用户安装,或者触发安装流程 showPostUpdateDialog() } }另外,如果用户开启了Google Play的自动更新(系统设置里的“自动更新应用”),Play商店会在后台自动下载更新并安装,不需要咱们额外开发,这是最理想的后台自动更新场景。
如果因为某些原因不能用Play Core,比如应用不在Google Play分发,或者需要更定制化的逻辑,那可以自己实现一套更新流程,但要注意Android的后台限制:
版本检查
首先得有一个后端接口,返回当前最新版本号和APK下载地址,咱们在后台定时检查(比如用WorkManager每天检查一次):// 用WorkManager创建周期性任务 val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) // 仅在WiFi下检查,省流量 .build() val periodicWorkRequest = PeriodicWorkRequestBuilder<VersionCheckWorker>(1, TimeUnit.DAYS) .setConstraints(constraints) .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork( "version_check", ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest )后台下载APK
检查到有新版本后,用DownloadManager在后台下载APK,这样系统会负责下载的后台调度,避免被系统杀死:val downloadManager = context.getSystemService(DOWNLOAD_SERVICE) as DownloadManager val request = DownloadManager.Request(Uri.parse(apkUrl)) .setTitle("应用更新") .setDescription("正在下载最新版本") .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI) .setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, "app_update.apk") val downloadId = downloadManager.enqueue(request)自动安装APK
下载完成后,通过广播接收器监听下载完成事件,然后触发安装流程。注意Android 8.0+需要申请REQUEST_INSTALL_PACKAGES权限,而且不能完全静默安装,必须弹出安装确认框:class DownloadCompleteReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val downloadId = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) ?: -1 if (downloadId == -1) return val downloadManager = context?.getSystemService(DOWNLOAD_SERVICE) as DownloadManager val query = DownloadManager.Query().setFilterById(downloadId) val cursor = downloadManager.query(query) if (cursor.moveToFirst()) { val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) if (status == DownloadManager.STATUS_SUCCESSFUL) { val apkPath = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)) // 触发安装 val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE) .setDataAndType(Uri.parse(apkPath), "application/vnd.android.package-archive") .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) context.startActivity(installIntent) } } cursor.close() } }
- 权限问题:Android 8.0+需要
REQUEST_INSTALL_PACKAGES权限,Android 10+需要处理存储权限或者用MediaStore来获取APK路径 - 后台限制:Android 6.0+的Doze模式和App Standby会限制后台任务,所以尽量用WorkManager、DownloadManager这些系统级的组件,避免自己开线程导致被杀死
- Google Play政策:如果应用在Google Play分发,不能强制静默更新,必须给用户选择权,否则可能会被下架
- 版本校验:下载APK后最好校验MD5或者SHA256,避免下载到篡改的安装包
内容的提问来源于stack exchange,提问作者fbdemo fbdemo1

