You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何为未上架应用商店的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_IMAGESREAD_MEDIA_VIDEO等,要根据下载的文件类型申请对应权限
  • iOS的企业证书:必须确保证书有效,而且用户需要在「设置-通用-VPN与设备管理」里信任你的企业证书才能安装
  • 安全性:内部服务器的下载链接最好做权限验证,比如只允许内部IP访问,或者加Token验证
  • 下载体验:尽量在WiFi环境下提示更新,避免用户流量消耗,可以加个流量检测逻辑

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

火山引擎 最新活动