306 lines
10 KiB
Markdown
306 lines
10 KiB
Markdown
# 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,
|
||
autoDownload: true,
|
||
autoInstall: false,
|
||
),
|
||
);
|
||
|
||
// 一行调用,自动拉取并展示升级对话框
|
||
AppUpgradeSimple.instance.checkUpdate(
|
||
context: context,
|
||
url: 'https://your-api.com/check-update',
|
||
params: {'channel': 'release'},
|
||
);
|
||
}
|
||
```
|
||
|
||
### 方式二:静默检查 + 由用户决定
|
||
|
||
```dart
|
||
final info = await AppUpgradeSimple.instance.checkUpdateSilent(
|
||
url: 'https://your-api.com/check-update',
|
||
params: {'platform': 'android'},
|
||
);
|
||
|
||
if (info != null && info.hasUpdate && context.mounted) {
|
||
// 再次调用一键方法以展示对话框(内部会重新请求一次最新信息)
|
||
await AppUpgradeSimple.instance.checkUpdate(
|
||
context: context,
|
||
url: 'https://your-api.com/check-update',
|
||
);
|
||
}
|
||
```
|
||
|
||
说明:当前公开 API 中未暴露独立的 `showUpgradeDialog()` 方法,静默检查用于“询问后再触发一键流程”的业务场景。
|
||
|
||
### 常用配置
|
||
|
||
```dart
|
||
// 内置多套配置:
|
||
AppUpgradeSimple.instance.configure(UpgradeConfig.auto); // 自动下载+自动安装
|
||
AppUpgradeSimple.instance.configure(UpgradeConfig.silent); // 静默检查
|
||
AppUpgradeSimple.instance.configure(UpgradeConfig.withPermission); // 安装前检查权限(传统)
|
||
|
||
// 自定义:
|
||
AppUpgradeSimple.instance.configure(const UpgradeConfig(
|
||
showNoUpdateToast: true,
|
||
autoDownload: true,
|
||
autoInstall: false,
|
||
installTimeout: 60,
|
||
));
|
||
```
|
||
|
||
## 🎨 UI 能力
|
||
|
||
- 发现新版本对话框(强制/非强制)
|
||
- 版本信息卡片(当前版本、新版本、APK 大小)
|
||
- 下载进度展示与可重试安装行为
|
||
- Android 上支持“应用市场选择”或“直接下载”两种路径
|
||
|
||
## ⚙️ Android 配置
|
||
|
||
### 1) 权限
|
||
|
||
在 `android/app/src/main/AndroidManifest.xml` 中添加:
|
||
|
||
```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.PROCESS_TEXT"/>
|
||
<data android:mimeType="text/plain"/>
|
||
</intent>
|
||
<!-- 允许打开浏览器处理 HTTP/HTTPS 链接(用于"前往浏览器下载"功能) -->
|
||
<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
|
||
<?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/) -->
|
||
<!-- This is accessible without WRITE_EXTERNAL_STORAGE permission on Android 10+ -->
|
||
<!-- 用于权限被拒绝时,使用应用私有目录存储下载的 APK -->
|
||
<external-files-path name="external_app_files" path="." />
|
||
</paths>
|
||
```
|
||
|
||
### 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")
|
||
}
|
||
```
|
||
|
||
## 📡 服务端返回协议
|
||
|
||
代码模型 `UpgradeInfo` 需要以下字段(关键字段必须):
|
||
|
||
```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": [
|
||
{"name":"华为应用市场","packageName":"com.huawei.appmarket","url":"appmarket://details?id=com.yourapp.package"}
|
||
]
|
||
}
|
||
```
|
||
|
||
- `versionBuildNumber` 与 `versionName` 为必填,插件会与当前应用版本进行对比自动计算 `hasUpdate`。
|
||
- `downloadUrl` 仅 Android 需要;`appStoreUrl` 仅 iOS 使用。
|
||
|
||
## 🔧 进阶能力
|
||
|
||
### 1) 网络配置
|
||
|
||
```dart
|
||
// 自动选择(Debug 绕过证书、Release 严格校验)
|
||
AppUpgradePlugin().configureHttp(HttpConfig.auto);
|
||
|
||
// 或手动:
|
||
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();
|
||
```
|
||
|
||
### 3) 安装策略(Android)
|
||
|
||
```dart
|
||
// 系统流程(推荐):系统处理权限并弹出安装确认
|
||
await AppUpgradePlugin().installApkWithSystemFlow(apkPath);
|
||
|
||
// 传统安装:需要事先自行处理安装权限
|
||
await AppUpgradePlugin().installApk(apkPath);
|
||
|
||
// 按配置策略安装
|
||
await AppUpgradePlugin().installApkWithConfig(
|
||
apkPath,
|
||
config: InstallConfig.smart,
|
||
);
|
||
```
|
||
|
||
策略对比:
|
||
|
||
- `systemFlow`:系统处理权限检查与确认,体验最佳
|
||
- `preCheckPermission`:先检查权限,无权时返回错误,便于精细控制
|
||
- `smart`:有权用预检查,无权走系统流程
|
||
|
||
## 🐛 常见问题
|
||
|
||
- 安装失败显示"解析包时出现问题":检查 APK 完整性、签名与架构匹配
|
||
- 权限申请失败:确认 Manifest 权限、FileProvider 配置、在 MaterialApp 环境调用
|
||
- 下载失败/进度不更新:检查网络、下载 URL 可用性、服务端是否支持断点
|
||
- iOS 不跳转:确认 `appStoreUrl` 为有效的 App Store 链接
|
||
- "前往浏览器下载"无反应:确认已在 AndroidManifest.xml 中添加 `<queries>` 声明(Android 11+ 必需)
|
||
- FileProvider 配置错误:确认 `file_paths.xml` 中已添加 `<external-files-path>` 配置,用于权限被拒绝时的备用存储路径
|
||
- Android 9 下载权限错误:插件会自动检测权限,无权限时使用应用私有目录,无需额外配置
|
||
|
||
## 📚 主要 API 清单
|
||
|
||
### AppUpgradeSimple
|
||
|
||
- `configure(UpgradeConfig)`:配置升级参数
|
||
- `checkUpdate({context, url, params, ...})`:检查更新并显示 UI
|
||
- `checkUpdateSilent({url, params})`:静默检查(不显示 UI)
|
||
- `preDownloadApk({url, onProgress})`:预下载 APK(Android)
|
||
- `findDownloadedApk(version)`:查找已下载的 APK(Android)
|
||
- `getAppInfo()`:获取当前应用信息
|
||
|
||
### AppUpgradePlugin(底层能力)
|
||
|
||
- `configureHttp(HttpConfig)`:网络层配置
|
||
- `downloadApk(url, onProgress)`:下载 APK(Android)
|
||
- `installApk(filePath)` / `installApkWithSystemFlow(filePath)` / `installApkWithConfig(filePath, config)`(Android)
|
||
- `openInstallPermissionSettings()`:跳转安装权限设置(Android)
|
||
- `getDeviceInfo()`、`getAndroidSdkVersion()`(Android)
|
||
- `goToAppStore(url)`:跳转到应用商店
|
||
- `checkMarketAvailable({packageName, marketPackage, url})`:检查应用市场是否可用(Android),用于判断设备是否有可用的应用市场
|
||
|
||
### PermissionHelper(Android)
|
||
|
||
- `checkAndRequestStoragePermission(context)`
|
||
- `checkAndRequestInstallPermission(context)`
|
||
- `checkAndRequestNotificationPermission(context)`
|
||
|
||
## 🤝 贡献
|
||
|
||
欢迎提交 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) |