17 KiB
17 KiB
App Upgrade Plugin
一款轻量、现代且易用的 Flutter 应用内更新插件。支持 Android 的"下载-安装"全流程,iOS 自动跳转 App Store。提供「一键检查更新」与「静默检查 + 用户决定」两种常见用法,并内置完善的权限处理与安装策略。
✨ 特性
- 🎯 智能平台适配:Android 直下直装,iOS 跳转 App Store
- 🔄 两种更新体验:非强制(可后台下载)与强制更新(阻塞式对话框)
- 🛡️ 权限适配完善:针对不同 Android 版本的存储、安装、通知权限自动处理
- 📱 现代化 UI:Material 风格对话框,进度与状态可视化
- 🌐 网络可配置:证书校验、超时、默认方法、Headers 等
- 🔧 安装策略灵活:系统流程/预检查权限/智能策略可选
- 🏪 应用市场支持:支持多应用市场白名单,智能检测设备已安装的市场
- 📦 三种更新方式:应用市场、浏览器下载、应用内下载
📦 安装
在 pubspec.yaml 中添加依赖:
dependencies:
app_upgrade_plugin: ^1.0.0
🚀 快速开始
方式一:一键检查更新(推荐)
这是最简单的方式,一行代码即可完成检查更新并显示升级对话框:
import 'package:app_upgrade_plugin/app_upgrade_plugin.dart';
void checkUpdate(BuildContext context) {
// 可选:一次性配置常用选项
AppUpgradeSimple.instance.configure(
const UpgradeConfig(
showNoUpdateToast: true,
autoInstall: false,
),
);
// 一行调用,自动拉取并展示升级对话框
AppUpgradeSimple.instance.checkUpdate(
context: context,
future: () async {
// 调用您的 API 获取版本信息
final response = await http.get('https://your-api.com/check-update');
final data = json.decode(response.body);
// 返回 AppUpgradeVersion 对象
return AppUpgradeVersion(
versionName: data['versionName'],
versionBuildNumber: data['versionBuildNumber'],
isForce: data['isForceUpdate'] ?? false,
updateContent: data['updateContent'],
downloadUrl: data['downloadUrl'],
appStoreUrl: data['appStoreUrl'],
apkSize: data['apkSize'],
apkMd5: data['apkMd5'],
appMarkets: (data['appMarkets'] as List?)
?.map((e) => AppMarket.fromString(e))
.toList(),
supportedMethods: [
AppUpgradeMethod.market,
AppUpgradeMethod.browser,
AppUpgradeMethod.inApp,
],
);
},
);
}
方式二:静默检查 + 由用户决定
先静默检查是否有更新,然后由用户决定是否显示升级对话框:
// 注意:当前版本不提供独立的静默检查方法
// 如果需要静默检查,请直接调用您的 API,然后手动判断是否需要显示对话框
final response = await http.get('https://your-api.com/check-update');
final data = json.decode(response.body);
// 手动比较版本
final serverVersion = data['versionBuildNumber'];
final currentVersion = await AppUpgradeSimple.instance.getAppInfo();
final currentBuildNumber = int.parse(currentVersion['buildNumber'] ?? '0');
if (serverVersion > currentBuildNumber) {
// 有新版本,显示升级对话框
await AppUpgradeSimple.instance.checkUpdate(
context: context,
future: () async {
return AppUpgradeVersion.fromJson(data);
},
);
}
常用配置
// 预设配置:
AppUpgradeSimple.instance.configure(UpgradeConfig.development); // 开发模式(详细日志+提示)
AppUpgradeSimple.instance.configure(UpgradeConfig.production); // 生产模式(静默+性能优化)
// 自定义配置:
AppUpgradeSimple.instance.configure(const UpgradeConfig(
showNoUpdateToast: true,
autoInstall: false,
installTimeout: 60,
enableDebugLog: true,
requireInstallPermission: false, // 默认不需要权限,直接安装
));
🎨 UI 能力
- 发现新版本对话框(强制/非强制)
- 强制更新:不可关闭,必须更新
- 非强制更新:可稍后更新,支持后台下载
- 版本信息卡片:显示当前版本、新版本、APK 大小
- 下载进度展示:实时显示下载进度百分比和状态
- 安装状态检测:自动检测安装结果,支持重试
- 更新内容展示:支持 Markdown 格式(粗体、斜体、代码块等)
- Android 更新方式选择:应用市场、浏览器下载、应用内下载
⚙️ Android 配置
1) 权限
在 android/app/src/main/AndroidManifest.xml 中添加:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- Android 13+ 通知权限(可选) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<!-- Android 9 写储存权限(SDK 28 及以下需要) -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
<!-- FileProvider(Android 7.0+ APK 安装必需) -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
<!-- Android 11+ 查询声明:允许打开浏览器处理 HTTP/HTTPS URL -->
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
</queries>
</manifest>
2) FileProvider 路径
创建 android/app/src/main/res/xml/file_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- External storage -->
<external-path name="external_files" path="." />
<!-- Internal app storage -->
<files-path name="files" path="." />
<!-- Cache directory -->
<cache-path name="cache" path="." />
<!-- External cache -->
<external-cache-path name="external_cache" path="." />
<!-- Downloads directory -->
<external-path name="downloads" path="Download/" />
<!-- External app-specific files directory (Android/data/包名/files/) -->
<!-- 用于权限被拒绝时,使用应用私有目录存储下载的 APK -->
<external-files-path name="external_app_files" path="." />
</paths>
3) Gradle(可选)
android {
compileSdk 34
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
}
📡 服务端返回协议
服务端需要返回包含以下字段的 JSON(关键字段必须):
{
"isForceUpdate": false,
"versionBuildNumber": 101,
"versionName": "1.0.1",
"updateContent": "1. 修复登录\n2. 优化UI\n3. 提升性能",
"downloadUrl": "https://your-cdn.com/app-release.apk",
"appStoreUrl": "https://apps.apple.com/app/id123456789",
"apkSize": 25165824,
"apkMd5": "d41d8cd98f00b204e9800998ecf8427e",
"appMarkets": ["huawei", "xiaomi", "oppo"],
"supportedMethods": ["market", "browser", "inApp"]
}
字段说明:
versionBuildNumber(必填):版本号(整数),用于版本比较versionName(必填):版本名称(字符串),如 "1.0.1"isForceUpdate(可选):是否强制更新,默认falseupdateContent(可选):更新内容说明,支持换行和 Markdown 格式downloadUrl(Android 必填):APK 下载地址appStoreUrl(iOS 必填):App Store 链接apkSize(可选):APK 文件大小(字节)apkMd5(可选):APK 文件的 MD5 值,用于校验appMarkets(可选):应用市场白名单,见下方说明supportedMethods(可选):支持的更新方式,默认全部支持
版本比较逻辑:
插件会优先比较 versionBuildNumber,如果相同则比较 versionName。如果服务端版本大于当前版本,则判定为有新版本。
应用市场白名单 (appMarkets)
appMarkets 用于限制支持的应用市场(Android),作为白名单使用。配置后,插件会:
- 检测设备已安装的应用市场
- 匹配白名单:只允许跳转到白名单中且设备已安装的应用市场
- 智能处理:
- 如果设备上没有白名单中的任何应用市场,提示用户"不支持当前设备的应用市场",引导用户选择其他更新方式(如浏览器下载、应用内下载)
- 如果设备有白名单中的应用市场,直接跳转到设备默认应用市场
配置示例:
// Dart 代码
appMarkets: [AppMarket.huawei, AppMarket.xiaomi, AppMarket.oppo]
// 服务端返回
"appMarkets": ["huawei", "xiaomi", "oppo"]
支持的应用市场类型:
| 值 | 显示名称 | 对应包名 |
|---|---|---|
googlePlay |
Google Play | com.android.vending |
huawei |
华为应用市场 | com.huawei.appmarket |
xiaomi |
小米应用商店 | com.xiaomi.market |
oppo |
OPPO软件商店 | com.oppo.market |
vivo |
vivo应用商店 | com.bbk.appstore |
tencent |
腾讯应用宝 | com.tencent.android.qqdownloader |
coolapk |
酷安 | com.coolapk.market |
不配置 appMarkets 的行为:
如果不配置 appMarkets,插件会使用默认行为:跳转到设备的默认应用市场(使用 market:// 协议)。
支持的更新方式 (supportedMethods)
supportedMethods 用于指定支持的更新方式,可选值:
market:应用市场更新browser:浏览器下载inApp:应用内下载
如果不配置,默认支持所有方式。如果只配置一种方式,将直接使用该方式,不会显示选择对话框。
🔧 进阶能力
1) 网络配置
// 自动选择(Debug 绕过证书、Release 严格校验)
AppUpgradePlugin().configureHttp(HttpConfig.auto);
// 开发环境配置(绕过证书验证)
AppUpgradePlugin().configureHttp(HttpConfig.development);
// 生产环境配置(严格证书验证)
AppUpgradePlugin().configureHttp(HttpConfig.production);
// 或手动配置:
AppUpgradePlugin().configureHttp(const HttpConfig(
ignoreCertificate: false,
enableLog: true,
connectTimeout: 30,
receiveTimeout: 60,
defaultMethod: 'GET',
headers: {'User-Agent': 'MyApp/1.0'},
));
2) 权限助手(Android)
import 'package:app_upgrade_plugin/core/permission_helper.dart';
// 检查并请求存储权限
final hasStorage = await PermissionHelper.checkAndRequestStoragePermission(context: context);
// 检查并请求安装权限
final hasInstall = await PermissionHelper.checkAndRequestInstallPermission(context: context);
// 检查并请求通知权限
final hasNotification = await PermissionHelper.checkAndRequestNotificationPermission(context: context);
// 精确跳转安装权限设置
await AppUpgradePlugin().openInstallPermissionSettings();
权限处理说明:
- 存储权限:Android 13+ 无需权限(使用应用私有目录),Android 10-12 会尝试请求但失败时使用私有目录,Android 9 及以下需要权限
- 安装权限:默认情况下(
requireInstallPermission: false),插件会直接调用系统安装流程,由系统处理权限检查。如果设置为true,会在安装前检查权限 - 通知权限:Android 13+ 需要,用于显示下载进度通知
3) 安装策略(Android)
// 系统流程(推荐):系统处理权限并弹出安装确认
await AppUpgradePlugin().installApkWithSystemFlow(apkPath);
// 传统安装:需要事先自行处理安装权限
await AppUpgradePlugin().installApk(apkPath);
// 按配置策略安装
await AppUpgradePlugin().installApkWithConfig(
apkPath,
config: InstallConfig.smart,
);
策略对比:
systemFlow:系统处理权限检查与确认,体验最佳(推荐)preCheckPermission:先检查权限,无权时返回错误,便于精细控制smart:有权用预检查,无权走系统流程
4) 预下载 APK
// 后台预下载 APK(不显示 UI)
final apkPath = await AppUpgradeSimple.instance.preDownloadApk(
url: 'https://your-cdn.com/app-release.apk',
onProgress: (progress) {
print('下载进度: ${progress.percentage}%');
},
);
if (apkPath != null) {
print('下载完成: $apkPath');
}
5) 查找已下载的 APK
// 查找指定版本的已下载 APK
final apkPath = await AppUpgradeSimple.instance.findDownloadedApk('1.0.1');
if (apkPath != null) {
// 直接安装
await AppUpgradePlugin().installApkWithSystemFlow(apkPath);
}
6) 清理下载缓存
// 清理所有已下载的 APK 文件
await AppUpgradeSimple.instance.clearDownloadCache();
🐛 常见问题
- 安装失败显示"解析包时出现问题":检查 APK 完整性、签名与架构匹配
- 权限申请失败:确认 Manifest 权限、FileProvider 配置、在 MaterialApp 环境调用
- 下载失败/进度不更新:检查网络、下载 URL 可用性、服务端是否支持断点续传
- iOS 不跳转:确认
appStoreUrl为有效的 App Store 链接 - "前往浏览器下载"无反应:确认已在 AndroidManifest.xml 中添加
<queries>声明(Android 11+ 必需) - FileProvider 配置错误:确认
file_paths.xml中已添加<external-files-path>配置,用于权限被拒绝时的备用存储路径 - Android 9 下载权限错误:插件会自动检测权限,无权限时使用应用私有目录,无需额外配置
- 安装检测超时:默认超时时间为 45 秒,可通过
UpgradeConfig.installTimeout调整
📚 主要 API 清单
AppUpgradeSimple(推荐使用)
configure(UpgradeConfig):配置升级参数checkUpdate({context, future, showNoUpdateToast, autoInstall, onComplete, config}):检查更新并显示 UIpreDownloadApk({url, onProgress}):预下载 APK(Android)findDownloadedApk(version):查找已下载的 APK(Android)getAppInfo():获取当前应用信息clearDownloadCache():清理下载缓存checkNetworkStatus():检查网络连接状态
AppUpgradePlugin(底层能力)
configureHttp(HttpConfig):网络层配置checkUpdate(url, {params}):检查更新(返回 UpgradeInfo)downloadApk(url, {onProgress, savePath}):下载 APK(Android)installApk(filePath):安装 APK(需要先处理权限)installApkWithSystemFlow(filePath):使用系统流程安装(推荐)installApkWithConfig(filePath, {config}):按配置策略安装openInstallPermissionSettings():跳转安装权限设置(Android)getDeviceInfo()、getAndroidSdkVersion():获取设备信息(Android)goToAppStore(url, {context}):跳转到应用商店getInstalledMarkets():获取设备已安装的应用市场列表(Android)getDownloadPath():获取下载目录路径checkApkExists(version, md5):检查指定版本的 APK 是否已下载
PermissionHelper(Android)
checkAndRequestStoragePermission(context):检查并请求存储权限checkAndRequestInstallPermission(context):检查并请求安装权限checkAndRequestNotificationPermission(context):检查并请求通知权限checkInstallPermission():检查安装权限状态
配置类
UpgradeConfig:升级配置(超时、自动安装、日志等)HttpConfig:HTTP 配置(证书、超时、Headers 等)InstallConfig:安装策略配置
模型类
AppUpgradeVersion:服务端返回的版本信息模型UpgradeInfo:内部使用的升级信息模型AppMarket:应用市场枚举AppUpgradeMethod:更新方式枚举DownloadProgress:下载进度信息
🤝 贡献
欢迎提交 Issue 与 Pull Request!
📄 许可证
MIT License