【重磅发布】flutter_chen_updater-版本升级更新
Flutter Chen Updater
一个功能强大的Flutter应用内更新插件,支持Android APK自动下载、安装和iOS跳转App Store。
✨ 特性
- ✅ 跨平台支持: Android APK自动更新,iOS跳转App Store
- ✅ 智能下载: 支持断点续传、文件校验、多重备用方案
- ✅ 权限管理: 自动处理Android安装权限、存储权限
- ✅ 强制更新: 支持可选更新和强制更新模式
- ✅ 进度监控: 实时下载进度回调
- ✅ 文件校验: MD5文件完整性验证
- ✅ 生命周期管理: 智能处理应用前后台切换
- ✅ 自定义UI: 支持自定义更新对话框
效果预览
📦 安装
在你的 pubspec.yaml
文件中添加依赖:
dependencies: flutter_chen_updater: ^1.0.0
然后运行:
flutter pub get
⚙️ 权限配置
Android
在 android/app/src/main/AndroidManifest.xml
中添加必要权限:
<uses-permission android:name=\"android.permission.INTERNET\" /><uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" android:maxSdkVersion=\"28\" /><uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" android:maxSdkVersion=\"28\" /><uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\" /><uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />
🚀 基础用法
1. 简单更新检查
import \'package:flutter_chen_updater/flutter_chen_updater.dart\';void checkForUpdate() { final updateInfo = UpdateInfo( version: \'1.1.0\', downloadUrl: \'https://example.com/app-v1.1.0.apk\', iosUrl: \'https://apps.apple.com/app/id123456789\', description: \'1. 修复已知问题\\n2. 优化用户体验\\n3. 新增功能特性\', isForceUpdate: false, ); Updater.checkAndUpdate( context, updateInfo, onAlreadyLatest: () => print(\'已是最新版本\'), onConfirm: () => print(\'用户确认更新\'), onCancel: () => print(\'用户取消更新\'), );}
2. 带进度监控的更新
void checkForUpdateWithProgress() { final updateInfo = UpdateInfo( version: \'1.1.0\', downloadUrl: \'https://example.com/app-v1.1.0.apk\', description: \'更新说明\', fileHash: \'abc123def456\', // 可选:文件MD5校验 hashAlgorithm: \'md5\', fileSize: 15 * 1024 * 1024, // 15MB ); Updater.checkAndUpdate( context, updateInfo, onProgress: (progress) { print(\'下载进度: ${(progress.progress * 100).toStringAsFixed(1)}%\'); print(\'已下载: ${progress.downloaded} / ${progress.total}\'); }, onConfirm: () => print(\'开始下载更新\'), );}
3. 强制更新示例
void forceUpdate() { final updateInfo = UpdateInfo( version: \'2.1.0\', description: \'重要安全更新,请立即升级\', downloadUrl: \'https://example.com/app-v2.1.0.apk\', isForceUpdate: true, // 强制更新,用户无法取消 ); Updater.checkAndUpdate(context, updateInfo);}
4. 自定义对话框
4.1 使用 dialogBuilder 自定义
Future<bool> customDialog(BuildContext context, UpdateInfo updateInfo) { return showDialog<bool>( context: context, barrierDismissible: !updateInfo.isForceUpdate, builder: (context) => AlertDialog( title: Text(\'发现新版本 ${updateInfo.version}\'), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(updateInfo.description), if (updateInfo.fileSize != null) Padding( padding: const EdgeInsets.only(top: 8.0), child: Text(\'大小: ${(updateInfo.fileSize! / 1024 / 1024).toStringAsFixed(1)}MB\'), ), ], ), actions: [ if (!updateInfo.isForceUpdate) TextButton( onPressed: () => Navigator.pop(context, false), child: const Text(\'稍后更新\'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), child: const Text(\'立即更新\'), ), ], ), ) ?? false;}void checkWithCustomDialog() { final updateInfo = UpdateInfo( version: \'1.1.0\', downloadUrl: \'https://example.com/app.apk\', description: \'重要更新说明\', ); Updater.checkAndUpdate( context, updateInfo, dialogBuilder: customDialog, );}
4.2 使用 UpdateDialog 灵活配置
void checkWithFlexibleDialog() { final updateInfo = UpdateInfo( version: \'1.2.0\', downloadUrl: \'https://example.com/app.apk\', description: \'• 修复重要安全漏洞\\n• 优化启动速度\\n• 新增夜间模式\', fileSize: 25 * 1024 * 1024, // 25MB ); showDialog<bool>( context: context, barrierDismissible: !updateInfo.isForceUpdate, builder: (context) => UpdateDialog( updateInfo: updateInfo, // 自定义标题 title: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( gradient: LinearGradient( colors: [Colors.blue, Colors.purple], ), ), child: Row( children: [ Icon(Icons.system_update, color: Colors.white), const SizedBox(width: 8), Text( \'重要更新 V${updateInfo.version}\', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), ], ), ), // 自定义内容 content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( \'更新内容\', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Text(updateInfo.description), const SizedBox(height: 12), if (updateInfo.fileSize != null) Container( padding: const EdgeInsets.symmetric(horizontal: 12,vertical: 6, ), decoration: BoxDecoration(color: Colors.grey.shade100,borderRadius: BorderRadius.circular(16), ), child: Text(\'安装包大小: ${(updateInfo.fileSize! / 1024 / 1024).toStringAsFixed(1)}MB\',style: Theme.of(context).textTheme.bodySmall, ), ), ], ), ), ], ), // 自定义底部操作栏 footer: Container( padding: const EdgeInsets.all(16), child: Row( children: [ if (!updateInfo.isForceUpdate) ...[ Expanded( child: OutlinedButton( onPressed: () => Navigator.pop(context, false), child: const Text(\'稍后提醒\'), ), ), const SizedBox(width: 12), ], Expanded( flex: updateInfo.isForceUpdate ? 1 : 1, child: ElevatedButton.icon( onPressed: () => Navigator.pop(context, true), icon: const Icon(Icons.download), label: const Text(\'立即更新\'), ), ), ], ), ), ), );}
5. 纯下载功能
void downloadOnly() { final updateInfo = UpdateInfo( version: \'1.1.0\', downloadUrl: \'https://example.com/app.apk\', description: \'更新包\', ); Updater.download(updateInfo).listen((progress) { if (progress.isCompleted && progress.filePath != null) { print(\'下载完成: ${progress.filePath}\'); // 稍后安装 Updater.installApk( progress.filePath!, onSuccess: () => print(\'安装成功\'), onError: (error) => print(\'安装失败: $error\'), ); } else if (progress.isFailed) { print(\'下载失败: ${progress.error}\'); } });}
6. 版本比较
void checkVersionUpdate() { final currentVersion = \'1.0.0\'; final newVersion = \'1.1.0\'; final needUpdate = Updater.needUpdate(currentVersion, newVersion); print(\'是否需要更新: $needUpdate\');}
📚 API 文档
UpdateInfo 类
更新信息配置类:
class UpdateInfo { final String version; // 新版本号 (必需) final String? downloadUrl; // Android APK下载链接 final String? iosUrl; // iOS App Store链接 final String description; // 更新说明 (必需) final bool isForceUpdate; // 是否强制更新 final String? fileHash; // 文件哈希值 (可选) final String? hashAlgorithm; // 哈希算法 (默认: \'md5\') final int? fileSize; // 文件大小 (字节) final Map<String, dynamic>? extra; // 额外数据}
Updater 类
主要更新器类:
静态方法
checkAndUpdate()
- 检查并更新应用download()
- 纯下载方法(不自动安装)installApk()
- 安装APK文件needUpdate()
- 版本比较cancelDownload()
- 取消下载dispose()
- 清理资源
DownloadProgress 类
下载进度信息:
class DownloadProgress { final int downloaded; // 已下载字节数 final int total; // 总字节数 final double progress; // 进度 (0.0 - 1.0) final DownloadStatus status; // 下载状态 final String? error; // 错误信息 final String? filePath; // 文件路径}
DownloadStatus 枚举
enum DownloadStatus { idle, // 空闲 downloading, // 下载中 paused, // 暂停 completed, // 完成 failed, // 失败 cancelled, // 取消 installing // 安装中}
🔧 高级功能
文件校验
插件支持MD5文件完整性校验:
final updateInfo = UpdateInfo( version: \'1.1.0\', downloadUrl: \'https://example.com/app.apk\', description: \'安全更新\', fileHash: \'a1b2c3d4e5f6...\', hashAlgorithm: \'md5\',);
权限处理
插件自动处理以下权限:
- 存储权限 (Android 9及以下)
- 安装权限 (Android 8+)
- 网络权限
对于缺失权限,插件会:
- 自动请求权限
- 引导用户到系统设置页面
- 监听应用生命周期自动重试
生命周期管理
插件智能处理应用前后台切换:
- 用户跳转权限设置后返回应用时自动重试安装
- 后台下载任务保持活跃
- 应用退出时自动清理资源
💡 错误处理
插件提供完善的错误处理机制:
Updater.checkAndUpdate( context, updateInfo, onProgress: (progress) { if (progress.isFailed) { // 处理下载失败 showDialog( context: context, builder: (_) => AlertDialog( title: const Text(\'下载失败\'), content: Text(progress.error ?? \'未知错误\'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text(\'确定\'), ), ], ), ); } },);
🚦 最佳实践
- 版本检查: 建议在应用启动时检查更新
- 网络判断: 在检查更新前判断网络状态
- 用户体验: 避免在关键操作时弹出更新提示
- 资源清理: 应用退出时调用
Updater.dispose()
- 错误日志: 记录更新过程中的错误信息用于调试
❓ 常见问题
Q: Android安装失败怎么办?
A: 检查是否授予了\"安装未知应用\"权限,插件会自动引导用户设置。
Q: 下载速度慢怎么办?
A: 插件使用Android系统下载管理器和HTTP备用方案,确保最佳下载体验。
Q: 如何支持增量更新?
A: 当前版本不支持增量更新,建议使用文件校验确保完整性。
Q: iOS如何实现自动更新?
A: iOS由于系统限制只能跳转App Store,无法实现APK式的自动更新。
⚠️ 注意事项
-
Android权限:
- Android 6.0+ 需要运行时申请存储权限
- Android 8.0+ 需要安装未知来源应用权限
- Android 10+ 使用作用域存储,无需存储权限
-
文件安全:
- 建议使用HTTPS下载链接
- 强烈推荐设置fileHash进行文件完整性校验
- 下载的APK文件会自动进行基础验证
-
用户体验:
- 避免在用户进行重要操作时弹出更新提示
- 强制更新应谨慎使用,仅在安全更新时使用
- 提供清晰的更新说明和文件大小信息
📄 许可证
MIT License