yx_app_upgrade_flutter/README.md

306 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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>
<!-- 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.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})`:预下载 APKAndroid
- `findDownloadedApk(version)`:查找已下载的 APKAndroid
- `getAppInfo()`:获取当前应用信息
### AppUpgradePlugin底层能力
- `configureHttp(HttpConfig)`:网络层配置
- `downloadApk(url, onProgress)`:下载 APKAndroid
- `installApk(filePath)` / `installApkWithSystemFlow(filePath)` / `installApkWithConfig(filePath, config)`Android
- `openInstallPermissionSettings()`跳转安装权限设置Android
- `getDeviceInfo()`、`getAndroidSdkVersion()`Android
- `goToAppStore(url)`:跳转到应用商店
- `checkMarketAvailable({packageName, marketPackage, url})`检查应用市场是否可用Android用于判断设备是否有可用的应用市场
### PermissionHelperAndroid
- `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)