远轩用FLUTTER使用APP更新插件
Go to file
豌杂 ec343386f1 111 2025-11-28 11:46:38 +08:00
android 修复优化BUG 适配更多机型 2025-11-27 12:17:30 +08:00
example 修复优化BUG 适配更多机型 2025-11-27 12:17:30 +08:00
ios first commit 2025-09-16 17:59:27 +08:00
lib 111 2025-11-28 11:46:38 +08:00
.gitignore first commit 2025-09-16 17:59:27 +08:00
.metadata first commit 2025-09-16 17:59:27 +08:00
CHANGELOG.md first commit 2025-09-16 17:59:27 +08:00
LICENSE first commit 2025-09-16 17:59:27 +08:00
MARKET_WHITELIST_SIMPLE.md 修复优化BUG 适配更多机型 2025-11-27 12:17:30 +08:00
README.md 修复优化BUG 适配更多机型 2025-11-27 12:17:30 +08:00
USAGE_GUIDE.md 请添加到说明文档中 2025-11-28 11:34:51 +08:00
analysis_options.yaml first commit 2025-09-16 17:59:27 +08:00
devtools_options.yaml first commit 2025-09-16 17:59:27 +08:00
pubspec.yaml 11 2025-11-25 13:42:11 +08:00

README.md

App Upgrade Plugin

一款轻量、现代且易用的 Flutter 应用内更新插件。支持 Android 的"下载-安装"全流程iOS 自动跳转 App Store。提供「一键检查更新」与「静默检查 + 用户决定」两种常见用法,并内置完善的权限处理与安装策略。

特性

  • 🎯 智能平台适配Android 直下直装iOS 跳转 App Store
  • 🔄 两种更新体验:非强制(可后台下载)与强制更新(阻塞式对话框)
  • 🛡️ 权限适配完善:针对不同 Android 版本的存储、安装、通知权限自动处理
  • 📱 现代化 UIMaterial 风格对话框,进度与状态可视化
  • 🌐 网络可配置证书校验、超时、默认方法、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>
        <!-- FileProviderAndroid 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(可选):是否强制更新,默认 false
  • updateContent(可选):更新内容说明,支持换行和 Markdown 格式
  • downloadUrlAndroid 必填APK 下载地址
  • appStoreUrliOS 必填App Store 链接
  • apkSize可选APK 文件大小(字节)
  • apkMd5可选APK 文件的 MD5 值,用于校验
  • appMarkets(可选):应用市场白名单,见下方说明
  • supportedMethods(可选):支持的更新方式,默认全部支持

版本比较逻辑:

插件会优先比较 versionBuildNumber,如果相同则比较 versionName。如果服务端版本大于当前版本,则判定为有新版本。

应用市场白名单 (appMarkets)

appMarkets 用于限制支持的应用市场Android作为白名单使用。配置后插件会

  1. 检测设备已安装的应用市场
  2. 匹配白名单:只允许跳转到白名单中且设备已安装的应用市场
  3. 智能处理
    • 如果设备上没有白名单中的任何应用市场,提示用户"不支持当前设备的应用市场",引导用户选择其他更新方式(如浏览器下载、应用内下载)
    • 如果设备有白名单中的应用市场,直接跳转到设备默认应用市场

配置示例:

// 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}):检查更新并显示 UI
  • preDownloadApk({url, onProgress}):预下载 APKAndroid
  • findDownloadedApk(version):查找已下载的 APKAndroid
  • getAppInfo():获取当前应用信息
  • clearDownloadCache():清理下载缓存
  • checkNetworkStatus():检查网络连接状态

AppUpgradePlugin底层能力

  • configureHttp(HttpConfig):网络层配置
  • checkUpdate(url, {params}):检查更新(返回 UpgradeInfo
  • downloadApk(url, {onProgress, savePath}):下载 APKAndroid
  • installApk(filePath):安装 APK需要先处理权限
  • installApkWithSystemFlow(filePath):使用系统流程安装(推荐)
  • installApkWithConfig(filePath, {config}):按配置策略安装
  • openInstallPermissionSettings()跳转安装权限设置Android
  • getDeviceInfo()getAndroidSdkVersion()获取设备信息Android
  • goToAppStore(url, {context}):跳转到应用商店
  • getInstalledMarkets()获取设备已安装的应用市场列表Android
  • getDownloadPath():获取下载目录路径
  • checkApkExists(version, md5):检查指定版本的 APK 是否已下载

PermissionHelperAndroid

  • checkAndRequestStoragePermission(context):检查并请求存储权限
  • checkAndRequestInstallPermission(context):检查并请求安装权限
  • checkAndRequestNotificationPermission(context):检查并请求通知权限
  • checkInstallPermission():检查安装权限状态

配置类

  • UpgradeConfig:升级配置(超时、自动安装、日志等)
  • HttpConfigHTTP 配置证书、超时、Headers 等)
  • InstallConfig:安装策略配置

模型类

  • AppUpgradeVersion:服务端返回的版本信息模型
  • UpgradeInfo:内部使用的升级信息模型
  • AppMarket:应用市场枚举
  • AppUpgradeMethod:更新方式枚举
  • DownloadProgress:下载进度信息

🤝 贡献

欢迎提交 Issue 与 Pull Request

📄 许可证

MIT License

🔗 参考