如何为未上架应用商店的Flutter内部应用实现自升级?求推荐库
Flutter内部应用自升级方案(无应用商店依赖)
嘿,这个场景我太熟了——内部工具类应用不上架官方商店,但又需要定期推更新对吧?完全可以自己搭建一套轻量的自升级体系,下面是我实践过的靠谱方案:
核心自升级逻辑
其实自升级的本质就是三个通用步骤,不管什么平台都适用:
- 版本检测:App启动时向你们的内部服务器拉取最新版本信息
- 版本对比:把本地当前版本和服务器返回的版本号做比对,判断是否需要更新
- 下载安装:引导用户下载安装包,触发系统的安装流程(Android和iOS处理细节不一样)
推荐的库组合
我不推荐那种大而全的封装库(很多默认依赖应用商店逻辑,还要改一堆配置),用几个轻量的主流库组合更灵活可控:
package_info_plus:用来获取本地App的版本号、包名等基础信息flutter_downloader:处理后台下载,支持Android通知栏进度、iOS后台下载,稳定性拉满permission_handler:处理Android的存储权限、iOS的相关权限申请url_launcher:iOS端用来打开企业证书的专属安装链接
如果嫌组合麻烦,也可以试试app_upgrade这个库,它已经封装了版本检测和下载逻辑,只需要对接你们的服务器接口就行,不过自定义程度会稍低一点。
具体实现步骤
1. 先搭好内部版本服务
首先你们需要一个内部服务器接口,返回最新版本的JSON信息,格式大概是这样:
{ "latestVersion": "1.2.0", "downloadUrl": "https://your-internal-server/app/release/app-release.apk", "updateLog": "- 修复了报表加载慢的问题\n- 新增部门权限管理功能", "forceUpdate": false }
这个接口要确保只有内部网络能访问,最好加个简单的Token验证防外部爬取。
2. 配置依赖库
在pubspec.yaml里添加依赖:
dependencies: package_info_plus: ^8.0.0 flutter_downloader: ^1.10.4 permission_handler: ^11.0.1 url_launcher: ^6.2.5
然后执行flutter pub get拉取依赖。
3. 版本检测逻辑
先获取本地当前版本,再请求服务器对比:
// 获取本地版本 final packageInfo = await PackageInfo.fromPackageInfo(); final currentVersion = packageInfo.version; // 请求服务器最新版本(这里用你自己的网络请求库,比如dio) final response = await Dio().get('https://your-internal-server/api/latest-version'); final latestVersion = response.data['latestVersion']; // 版本对比逻辑(注意不要直接字符串对比,要拆成数字比较,比如"1.10.0"比"1.9.0"新) bool needUpdate = compareVersions(currentVersion, latestVersion);
版本比较的工具函数可以自己写,也可以用version库来简化开发。
4. 下载与安装
Android端
用flutter_downloader下载APK,下载完成后调用系统Intent启动安装:
// 申请存储权限 await Permission.storage.request(); // 开始下载 final taskId = await FlutterDownloader.enqueue( url: downloadUrl, savedDir: '/storage/emulated/0/Download', showNotification: true, openFileFromNotification: true, ); // 监听下载完成,手动触发安装(可选) FlutterDownloader.registerCallback((id, status, progress) { if (status == DownloadTaskStatus.complete && id == taskId) { // 调用Intent安装APK final intent = Intent( action: IntentAction.view, data: Uri.parse('file://$savedDir/app-release.apk'), type: 'application/vnd.android.package-archive', ); intent.addFlags(Flag.FLAG_ACTIVITY_NEW_TASK); await AndroidIntent(intent: intent).launch(); } });
别忘了在AndroidManifest.xml里配置flutter_downloader需要的服务和权限。
iOS端
iOS不能直接下载IPA安装,必须用企业开发者证书打包,然后提供一个itms-services链接,用url_launcher打开:
// 企业证书的安装链接,指向你的plist文件 final installUrl = 'itms-services://?action=download-manifest&url=https://your-internal-server/manifest.plist'; if (await canLaunchUrl(Uri.parse(installUrl))) { await launchUrl(Uri.parse(installUrl)); }
plist文件的格式要符合Apple的要求,里面要包含IPA的下载地址、bundle ID等信息。
5. 可选:强制更新
如果某个版本有重大bug,需要强制用户更新,可以在服务器返回的信息里加forceUpdate: true,然后在App里判断:
if (response.data['forceUpdate']) { // 弹出不可关闭的更新弹窗,屏蔽所有其他操作 showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( title: Text('必须更新'), content: Text('此版本存在重大问题,请立即更新'), actions: [ TextButton( onPressed: () => startDownload(), child: Text('立即更新'), ) ], ), ); }
注意事项
- Android 13+的权限适配:存储权限已经改成了
READ_MEDIA_IMAGES、READ_MEDIA_VIDEO等,要根据下载的文件类型申请对应权限 - iOS的企业证书:必须确保证书有效,而且用户需要在「设置-通用-VPN与设备管理」里信任你的企业证书才能安装
- 安全性:内部服务器的下载链接最好做权限验证,比如只允许内部IP访问,或者加Token验证
- 下载体验:尽量在WiFi环境下提示更新,避免用户流量消耗,可以加个流量检测逻辑
内容的提问来源于stack exchange,提问作者Risfat




