Flutter Chen Updater
一个功能强大的Flutter应用内更新插件,支持Android APK自动下载、安装和iOS跳转App Store。
✨ 特性
- ✅ 跨平台支持: Android APK自动更新,iOS跳转App Store
- ✅ 智能下载: 支持断点续传、文件校验、多重备用方案
- ✅ 权限管理: 自动处理Android安装权限、存储权限
- ✅ 强制更新: 支持可选更新和强制更新模式
- ✅ 进度监控: 实时下载进度回调
- ✅ 文件校验: MD5文件完整性验证
- ✅ 生命周期管理: 智能处理应用前后台切换
- ✅ 自定义UI: 支持自定义更新对话框
效果预览

📦 安装
在你的 pubspec.yaml
文件中添加依赖:
yaml
dependencies:
flutter_chen_updater: ^1.0.0
然后运行:
bash
flutter pub get
⚙️ 权限配置
Android
在 android/app/src/main/AndroidManifest.xml
中添加必要权限:
xml
<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 存储权限 (Android 9及以下) -->
<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. 简单更新检查
dart
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. 带进度监控的更新
dart
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. 强制更新示例
dart
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 自定义
dart
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 灵活配置
dart
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. 纯下载功能
dart
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. 版本比较
dart
void checkVersionUpdate() {
final currentVersion = '1.0.0';
final newVersion = '1.1.0';
final needUpdate = Updater.needUpdate(currentVersion, newVersion);
print('是否需要更新: $needUpdate');
}
📚 API 文档
UpdateInfo 类
更新信息配置类:
dart
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 类
下载进度信息:
dart
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 枚举
dart
enum DownloadStatus {
idle, // 空闲
downloading, // 下载中
paused, // 暂停
completed, // 完成
failed, // 失败
cancelled, // 取消
installing // 安装中
}
🔧 高级功能
文件校验
插件支持MD5文件完整性校验:
dart
final updateInfo = UpdateInfo(
version: '1.1.0',
downloadUrl: 'https://example.com/app.apk',
description: '安全更新',
fileHash: 'a1b2c3d4e5f6...',
hashAlgorithm: 'md5',
);
权限处理
插件自动处理以下权限:
- 存储权限 (Android 9及以下)
- 安装权限 (Android 8+)
- 网络权限
对于缺失权限,插件会:
- 自动请求权限
- 引导用户到系统设置页面
- 监听应用生命周期自动重试
生命周期管理
插件智能处理应用前后台切换:
- 用户跳转权限设置后返回应用时自动重试安装
- 后台下载任务保持活跃
- 应用退出时自动清理资源
💡 错误处理
插件提供完善的错误处理机制:
dart
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