如何通过编程实现App自动更新(下载安装最新版本)并推送通知?求示例代码
App自动更新实现方案(无需启动应用+更新后通知)
核心逻辑概述
要实现无需打开应用的自动更新,核心流程为:后台定期检查版本→对比版本号触发后台下载→自动/引导安装→发送更新完成通知。Android和iOS系统限制差异较大,实现方式需分开处理。
是否需要第三方平台?
- 可选自建方案:搭建简单的版本管理服务器(存储最新版本号、安装包下载地址),完全可控,无需依赖第三方;
- 第三方平台:如蒲公英、FIR.im等,可直接调用其API获取版本信息、托管安装包,省去服务器维护成本,适合快速落地。
Android 实现示例(Kotlin)
Android支持后台任务执行,推荐用WorkManager实现稳定的后台版本检查与下载,避免进程被系统杀死。
1. 权限配置(AndroidManifest.xml)
<!-- 网络权限 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 后台下载权限 --> <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" /> <!-- 安装未知来源应用(Android 10+需动态申请) --> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <!-- 通知权限(Android 13+需动态申请) --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
2. 后台版本检查任务
用WorkManager设置每日一次的版本检查:
class UpdateCheckWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { // 1. 从服务器拉取最新版本信息(替换为真实接口) val latestVersion = "2.0.0" val currentVersion = packageManager.getPackageInfo(packageName, 0).versionName val apkDownloadUrl = "https://your-server.com/app/latest.apk" // 2. 版本对比,需更新则启动下载任务 if (latestVersion > currentVersion) { val downloadRequest = OneTimeWorkRequestBuilder<ApkDownloadWorker>() .setInputData(workDataOf("APK_URL" to apkDownloadUrl)) .build() WorkManager.getInstance(applicationContext).enqueue(downloadRequest) } return Result.success() } } // App首次启动时调用,开启定期检查 fun scheduleUpdateCheck(context: Context) { val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) // 仅联网时执行 .build() val periodicRequest = PeriodicWorkRequestBuilder<UpdateCheckWorker>(24, TimeUnit.HOURS) .setConstraints(constraints) .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork( "DailyUpdateCheck", ExistingPeriodicWorkPolicy.REPLACE, periodicRequest ) }
3. 后台下载与安装+通知
class ApkDownloadWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { val apkUrl = inputData.getString("APK_URL") ?: return Result.failure() val downloadDir = applicationContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) val apkFile = File(downloadDir, "latest_app.apk") try { // 下载APK(简化实现,实际可添加断点续传、进度监听) val url = URL(apkUrl) val connection = url.openConnection() as HttpURLConnection connection.inputStream.use { input -> FileOutputStream(apkFile).use { output -> input.copyTo(output) } } // 启动安装并发送通知 installApk(apkFile) sendUpdateCompleteNotification() return Result.success() } catch (e: Exception) { e.printStackTrace() return Result.retry() } } private fun installApk(apkFile: File) { val installIntent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive") addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } applicationContext.startActivity(installIntent) } private fun sendUpdateCompleteNotification() { val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Android 8.0+ 创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( "UPDATE_CHANNEL", "应用更新通知", NotificationManager.IMPORTANCE_DEFAULT ) notificationManager.createNotificationChannel(channel) } val launchIntent = applicationContext.packageManager.getLaunchIntentForPackage(applicationContext.packageName) val pendingIntent = PendingIntent.getActivity( applicationContext, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE ) val notification = NotificationCompat.Builder(applicationContext, "UPDATE_CHANNEL") .setContentTitle("应用已更新") .setContentText("最新版本安装完成,点击打开应用") .setSmallIcon(R.drawable.ic_notification) .setContentIntent(pendingIntent) .build() notificationManager.notify(1, notification) } }
iOS 实现说明
iOS系统对后台操作限制严格,无法实现完全静默更新,仅能通过以下方式实现近似需求:
- App Store自动更新:用户开启「自动下载App更新」后,iOS会在后台自动下载安装更新,完成后推送系统通知,无需用户打开应用;
- 企业版App:可自建服务器检查版本、下载IPA,但安装仍需用户手动确认(iOS禁止静默安装)。
企业版版本检查示例(Swift)
import UIKit import BackgroundTasks class UpdateManager { static let shared = UpdateManager() func checkForUpdate() { // 从服务器拉取版本信息(替换为真实接口) guard let url = URL(string: "https://your-server.com/version.json") else { return } URLSession.shared.dataTask(with: url) { data, _, error in guard let data = data, error == nil else { return } do { let versionInfo = try JSONDecoder().decode(AppVersionInfo.self, from: data) let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" if versionInfo.latestVersion > currentVersion { self.downloadAndPromptInstall(ipaUrl: versionInfo.ipaUrl) } } catch { print("解析版本信息失败: \(error)") } }.resume() } private func downloadAndPromptInstall(ipaUrl: String) { // 下载IPA(简化实现) guard let url = URL(string: ipaUrl) else { return } URLSession.shared.downloadTask(with: url) { localUrl, _, error in guard localUrl != nil, error == nil else { return } // 引导用户到企业分发页面安装 let installUrl = URL(string: "itms-services://?action=download-manifest&url=https://your-server.com/manifest.plist")! DispatchQueue.main.async { UIApplication.shared.open(installUrl) } // 发送更新通知(需用户授权通知权限) self.sendUpdateNotification() }.resume() } private func sendUpdateNotification() { let content = UNMutableNotificationContent() content.title = "应用更新完成" content.body = "最新版本已准备就绪,点击查看" let request = UNNotificationRequest(identifier: "UpdateComplete", content: content, trigger: nil) UNUserNotificationCenter.current().add(request) } } // 版本信息模型 struct AppVersionInfo: Codable { let latestVersion: String let ipaUrl: String } // App启动时注册后台更新检查任务 @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 注册后台刷新任务 BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.yourapp.updatecheck", using: nil) { task in self.handleUpdateCheck(task: task as! BGAppRefreshTask) } scheduleNextUpdateCheck() return true } private func scheduleNextUpdateCheck() { let request = BGAppRefreshTaskRequest(identifier: "com.yourapp.updatecheck") request.earliestBeginDate = Date(timeIntervalSinceNow: 86400) // 24小时后执行 do { try BGTaskScheduler.shared.submit(request) } catch { print("提交更新检查任务失败: \(error)") } } private func handleUpdateCheck(task: BGAppRefreshTask) { UpdateManager.shared.checkForUpdate() task.setTaskCompleted(success: true) scheduleNextUpdateCheck() // 重新调度下一次检查 } }
关键注意事项
- Android:Android 12+对后台启动Activity有严格限制,安装应用时可能需要用户手动确认;动态权限需提前向用户申请;
- iOS:App Store审核不允许自定义更新逻辑,仅企业版、TestFlight应用可使用自建更新流程。
内容的提问来源于stack exchange,提问作者cb_mobile
相关产品推荐
相关产品推荐

