# App Upgrade Plugin 一款轻量、现代且易用的 Flutter 应用内更新插件。支持 Android 的"下载-安装"全流程,iOS 自动跳转 App Store。提供「一键检查更新」与「静默检查 + 用户决定」两种常见用法,并内置完善的权限处理与安装策略。 ## ✨ 特性 - **🎯 智能平台适配**:Android 直下直装,iOS 跳转 App Store - **🔄 两种更新体验**:非强制(可后台下载)与强制更新(阻塞式对话框) - **🛡️ 权限适配完善**:针对不同 Android 版本的存储、安装、通知权限自动处理 - **📱 现代化 UI**:Material 风格对话框,进度与状态可视化 - **🌐 网络可配置**:证书校验、超时、默认方法、Headers 等 - **🔧 安装策略灵活**:系统流程/预检查权限/智能策略可选 - **🏪 应用市场支持**:支持多应用市场白名单,智能检测设备已安装的市场 - **📦 三种更新方式**:应用市场、浏览器下载、应用内下载 ## 📦 安装 在 `pubspec.yaml` 中添加依赖: ```yaml dependencies: app_upgrade_plugin: ^1.0.0 ``` ## 🚀 快速开始 ### 方式一:一键检查更新(推荐) 这是最简单的方式,一行代码即可完成检查更新并显示升级对话框: ```dart 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, ], ); }, ); } ``` ### 方式二:静默检查 + 由用户决定 先静默检查是否有更新,然后由用户决定是否显示升级对话框: ```dart // 注意:当前版本不提供独立的静默检查方法 // 如果需要静默检查,请直接调用您的 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); }, ); } ``` ### 常用配置 ```dart // 预设配置: 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` 中添加: ```xml ``` ### 2) FileProvider 路径 创建 `android/app/src/main/res/xml/file_paths.xml`: ```xml ``` ### 3) Gradle(可选) ```kotlin 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(关键字段必须): ```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`(可选):是否强制更新,默认 `false` - `updateContent`(可选):更新内容说明,支持换行和 Markdown 格式 - `downloadUrl`(Android 必填):APK 下载地址 - `appStoreUrl`(iOS 必填):App Store 链接 - `apkSize`(可选):APK 文件大小(字节) - `apkMd5`(可选):APK 文件的 MD5 值,用于校验 - `appMarkets`(可选):应用市场白名单,见下方说明 - `supportedMethods`(可选):支持的更新方式,默认全部支持 **版本比较逻辑:** 插件会优先比较 `versionBuildNumber`,如果相同则比较 `versionName`。如果服务端版本大于当前版本,则判定为有新版本。 ### 应用市场白名单 (appMarkets) `appMarkets` 用于限制支持的应用市场(Android),作为白名单使用。配置后,插件会: 1. **检测设备已安装的应用市场** 2. **匹配白名单**:只允许跳转到白名单中且设备已安装的应用市场 3. **智能处理**: - 如果设备上没有白名单中的任何应用市场,提示用户"不支持当前设备的应用市场",引导用户选择其他更新方式(如浏览器下载、应用内下载) - 如果设备有白名单中的应用市场,直接跳转到设备默认应用市场 **配置示例:** ```dart // 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) 网络配置 ```dart // 自动选择(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) ```dart 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) ```dart // 系统流程(推荐):系统处理权限并弹出安装确认 await AppUpgradePlugin().installApkWithSystemFlow(apkPath); // 传统安装:需要事先自行处理安装权限 await AppUpgradePlugin().installApk(apkPath); // 按配置策略安装 await AppUpgradePlugin().installApkWithConfig( apkPath, config: InstallConfig.smart, ); ``` **策略对比:** - `systemFlow`:系统处理权限检查与确认,体验最佳(推荐) - `preCheckPermission`:先检查权限,无权时返回错误,便于精细控制 - `smart`:有权用预检查,无权走系统流程 ### 4) 预下载 APK ```dart // 后台预下载 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 ```dart // 查找指定版本的已下载 APK final apkPath = await AppUpgradeSimple.instance.findDownloadedApk('1.0.1'); if (apkPath != null) { // 直接安装 await AppUpgradePlugin().installApkWithSystemFlow(apkPath); } ``` ### 6) 清理下载缓存 ```dart // 清理所有已下载的 APK 文件 await AppUpgradeSimple.instance.clearDownloadCache(); ``` ## 🐛 常见问题 - **安装失败显示"解析包时出现问题"**:检查 APK 完整性、签名与架构匹配 - **权限申请失败**:确认 Manifest 权限、FileProvider 配置、在 MaterialApp 环境调用 - **下载失败/进度不更新**:检查网络、下载 URL 可用性、服务端是否支持断点续传 - **iOS 不跳转**:确认 `appStoreUrl` 为有效的 App Store 链接 - **"前往浏览器下载"无反应**:确认已在 AndroidManifest.xml 中添加 `` 声明(Android 11+ 必需) - **FileProvider 配置错误**:确认 `file_paths.xml` 中已添加 `` 配置,用于权限被拒绝时的备用存储路径 - **Android 9 下载权限错误**:插件会自动检测权限,无权限时使用应用私有目录,无需额外配置 - **安装检测超时**:默认超时时间为 45 秒,可通过 `UpgradeConfig.installTimeout` 调整 ## 📚 主要 API 清单 ### AppUpgradeSimple(推荐使用) - `configure(UpgradeConfig)`:配置升级参数 - `checkUpdate({context, future, showNoUpdateToast, autoInstall, onComplete, config})`:检查更新并显示 UI - `preDownloadApk({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 ## 🔗 参考 - [Flutter 官网](https://flutter.dev) - [Android 安装权限文档](https://developer.android.com/reference/android/Manifest.permission#REQUEST_INSTALL_PACKAGES) - [FileProvider 使用指南](https://developer.android.com/reference/androidx/core/content/FileProvider)