GeneralUpdate.Maui.Android
命名空间: GeneralUpdate.Maui.Android | 主要入口: GeneralUpdateBootstrap.CreateDefault() / AddGeneralUpdateMauiAndroid() | NuGet 包: GeneralUpdate.Maui.Android
1. 组件简介
1.1 组件概述
GeneralUpdate.Maui.Android 是面向 .NET MAUI 应用的 Android 平台自动更新组件,为 Android APK 提供版本发现、可恢复下载、SHA256 完整性校验以及系统 Package Installer 触发的一站式更新编排。
与桌面应用的文件替换式更新不同,Android APK 更新必须经由系统 Package Installer 完成。该组件封装了这一平台差异,并提供两阶段 API:ValidateAsync 做版本检查,ExecuteUpdateAsync 串起下载→校验→安装的完整流程。
核心能力:
| 能力 | 说明 |
|---|---|
| 版本对比检查 | 内置 System.Version 解析,自动判断当前版本是否低于目标版本 |
| 可恢复 APK 下载 | HttpRangeDownloader 基于 HTTP Range 请求头实现断点续传,支持进度报告 |
| SHA256 完整性校验 | 下载后自动计算文件 SHA256 与服务端哈希比对,损坏文件自动删除 |
| 系统安装器触发 | AndroidApkInstaller 通过 FileProvider + Intent 启动系统 Package Installer |
| DI 容器集成 | AddGeneralUpdateMauiAndroid() 扩展方法一键注册所有服务到 IServiceCollection |
| HTTP 传输配置 | HttpDownloadOptions 支持 SSL 证书策略、代理、超时、认证,支持指数退避重试 |
| 多协议认证 | 支持 HMAC-SHA256、Bearer Token、API Key、HTTP Basic 四种认证方案 |
| 事件通知 | 版本发现、下载进度、完成阶段、失败原因等全方位事件 |
| 并发安全 | ExecuteUpdateAsync 内置 Interlocked 并发保护,重复调用直接返回 AlreadyInProgress |
| 临时文件管理 | 下载使用 .downloading 临时扩展名,完成后原子替换为目标文件 |
解决的业务痛点:
- MAUI Android 应用需要内置自动更新能力,但 APK 安装必须绕过 Google Play 通过系统安装器完成
- 大 APK 下载过程中网络不稳定,需要断点续传减少用户流量消耗
- 需要确保下载的 APK 未被篡改或损坏,保障更新安全
- 需要与 MAUI 的 DI 容器深度集成,简化接入代码
Android 平台无法像桌面端那样直接替换可执行文件。APK 必须通过 Android Package Installer 安装,系统会处理签名验证和应用替换。MAUI 组件封装了这一差异,但 APK 签名、版本号递增 仍然需要你在构建流水线中保证。
业务使用场景:
- MAUI Android 应用的自动更新(企业内部分发、Beta 测试、旁加载)
- 需要通过 CDN / OSS 分发 APK 包的应用
- 需要 DI 容器管理的 MAUI 应用
1.2 环境与依赖
| 项目 | 说明 |
|---|---|
| NuGet 包 | GeneralUpdate.Maui.Android |
| 目标框架 | net10.0 + net10.0-android(多目标;Android 最低 API 21) |
| 依赖包 | Microsoft.Extensions.DependencyInjection.Abstractions、Microsoft.Extensions.Http、Xamarin.AndroidX.Core |
| 兼容性 | Android 5.0 (API 21) 及以上版本 |
2. 组件功能列表
| 功能名称 | 功能描述 | 类型 | 是否必填 | 备注限制 |
|---|---|---|---|---|
| 版本对比检查 | 对比当前版本与目标版本,判断是否有更新可用 | 基础 | 必选 | ValidateAsync,基于 System.Version 解析 |
| 更新执行 | 串起下载→校验→安装全流程 | 基础 | 必选 | ExecuteUpdateAsync,并发保护 |
| APK 可恢复下载 | HTTP Range 断点续传 + 进度报告 | 基础 | 自动 | HttpRangeDownloader |
| SHA256 校验 | 下载后自动校验,损坏文件自动删除 | 基础 | 自动 | 通过 IHashValidator,支持进度回调 |
| APK 安装触发 | FileProvider + Intent 启动系统安装器 | 基础 | 自动 | AndroidApkInstaller,自动检查安装权限 |
| DI 容器集成 | 一键注册所有更新服务 | 拓展 | 推荐 | AddGeneralUpdateMauiAndroid() |
| HTTP 传输配置 | SSL、代理、超时、重试、认证 | 拓展 | 可选 | HttpDownloadOptions |
| 多协议认证 | HMAC-SHA256 / Bearer / API Key / Basic | 拓展 | 可选 | 全局或单包粒度配置 |
| 进度通知 | 下载字节数、速度、百分比、剩余时间 | 基础 | 可选 | IProgress<DownloadStatistics> 回调 |
| 完成通知 | 各完成阶段(下载完成、校验完成、安装触发、工作流完成) | 基础 | 可选 | AddListenerUpdateCompleted |
| 失败通知 | 失败原因分类、异常信息 | 基础 | 可选 | AddListenerUpdateFailed |
| 验证通知 | 发现可用更新时触发 | 基础 | 可选 | AddListenerValidate |
| 状态查询 | 实时查询当前更新状态 | 基础 | 可选 | CurrentState 属性 |
| 并发保护 | 防止重复执行更新操作 | 基础 | 自动 | Interlocked 原子操作 |
| 损坏文件自动清理 | 校验失败自动删除损坏包 | 拓展 | 可选 | UpdateOptions.DeleteCorruptedPackageOnFailure |
| 进度报告间隔控制 | 自定义进度回调频率 | 拓展 | 可选 | UpdateOptions.ProgressReportInterval |
| 自定义下载器 | 自定义下载实现 | 拓展 | 可选 | 实现 IUpdateDownloader |
| 自定义哈希验证 | 自定义哈希实现 | 拓展 | 可选 | 实现 IHashValidator |
| 自定义安装器 | 自定义安装逻辑 | 拓展 | 可选 | 实现 IApkInstaller |
| 自定义存储提供器 | 自定义文件路径和存储操作 | 拓展 | 可选 | 实现 IUpdateStorageProvider |
| 自定义日志 | 自定义日志输出 | 拓展 | 可选 | 实现 IUpdateLogger |
| 自定义 SSL 策略 | 自定义 HTTPS 证书校验 | 拓展 | 可选 | 实现 ISslValidationPolicy |
| 自定义 HTTP 认证 | 自定义 HTTP 请求认证 | 拓展 | 可选 | 实现 IHttpAuthProvider |
3. API 配置说明
3.1 配置字段(属性 Props)
UpdateOptions:
| 字段名 | 数据类型 | 默认值 | 是否必填 | 说明 |
|---|---|---|---|---|
CurrentVersion | string | "" | 是 | 当前应用版本号 |
DownloadDirectory | string? | null | 可选 | 下载目录,为空时自动选择 |
TemporaryFileExtension | string | ".downloading" | 可选 | 临时下载文件扩展名 |
DeleteCorruptedPackageOnFailure | bool | true | 可选 | 校验失败时自动删除损坏包 |
ProgressReportInterval | TimeSpan | 500ms | 可选 | 进度报告间隔 |
InstallOptions | AndroidInstallOptions | new() | 可选 | 安装选项 |
AndroidInstallOptions:
| 字段名 | 数据类型 | 默认值 | 是否必填 | 说明 |
|---|---|---|---|---|
FileProviderAuthority | string | "" | 是 | FileProvider authority,需与 AndroidManifest 一致 |
MimeType | string | "application/vnd.android.package-archive" | 可选 | APK 文件的 MIME 类型 |
HttpDownloadOptions:
| 字段名 | 数据类型 | 默认值 | 是否必填 | 说明 |
|---|---|---|---|---|
SslValidationPolicy | ISslValidationPolicy? | null | 可选 | 自定义 SSL 证书验证策略 |
DownloadTimeout | TimeSpan | 10min | 可选 | 整体下载超时 |
Proxy | IWebProxy? | null | 可选 | HTTP 代理 |
UseProxy | bool | false | 可选 | 是否启用代理 |
AuthProvider | IHttpAuthProvider? | null | 可选 | 全局 HTTP 认证提供器 |
UpdatePackageInfo:
| 字段名 | 数据类型 | 默认值 | 是否必填 | 说明 |
|---|---|---|---|---|
Version | string | "" | 是 | 目标版本号 |
DownloadUrl | string | "" | 是 | APK 下载地址 |
Sha256 | string | "" | 是 | SHA256 哈希值 |
PackageSize | long? | null | 可选 | 包大小(字节) |
ApkFileName | string? | null | 可选 | APK 文件名 |
ForceUpdate | bool | false | 可选 | 是否强制更新 |
VersionName | string? | null | 可选 | 展示名称 |
ReleaseNotes | string? | null | 可选 | 发布说明 |
PublishTime | DateTimeOffset? | null | 可选 | 发布时间 |
AuthScheme | AuthScheme? | null | 可选 | 认证方案 |
AuthToken | string? | null | 可选 | 认证令牌 |
AuthSecretKey | string? | null | 可选 | HMAC 密钥 |
BasicUsername | string? | null | 可选 | Basic 用户名 |
BasicPassword | string? | null | 可选 | Basic 密码 |
UpdateState 枚举:
| 枚举值 | 说明 |
|---|---|
None | 初始/空闲状态 |
Checking | 正在检查更新 |
UpdateAvailable | 发现可用更新 |
Downloading | 正在下载 |
Verifying | 正在校验 |
ReadyToInstall | 准备安装 |
Installing | 正在安装 |
Completed | 更新完成 |
Failed | 更新失败 |
Canceled | 已取消 |
UpdateFailureReason 枚举:
| 枚举值 | 说明 |
|---|---|
Unknown | 未知错误 |
InvalidInput | 输入参数无效 |
AlreadyInProgress | 已有更新操作正在进行 |
Network | 网络错误 |
Download | 下载错误 |
FileAccess | 文件访问错误 |
IntegrityCheckFailed | 完整性校验失败 |
InstallPermissionDenied | 安装权限被拒绝 |
Installation | 安装过程错误 |
Canceled | 用户取消 |
NoUpdateAvailable | 无可用更新 |
UpdateCompletionStage 枚举:
| 枚举值 | 说明 |
|---|---|
DownloadCompleted | 下载完成 |
VerificationCompleted | 校验完成 |
InstallationTriggered | 安装器已启动 |
WorkflowCompleted | 工作流完成 |
3.2 实例方法
GeneralUpdateBootstrap(静态工厂):
| 方法名 | 入参明细 | 使用场景 | 注意事项 |
|---|---|---|---|
CreateDefault(HttpClient?, IUpdateLogger?, HttpDownloadOptions?) | httpClient — 可选外部 HttpClient;logger — 可选日志器;httpOptions — 可选 HTTP 配置 | 创建默认的 Android 更新引导实例 | httpOptions 生效时 httpClient 参数被忽略 |
AddGeneralUpdateMauiAndroid(IServiceCollection, HttpClient?) | services — DI 容器;httpClient — 可选外部 HttpClient | 在 MAUI DI 容器中注册所有更新服务 | 返回 IServiceCollection 支持链式调用 |
IAndroidBootstrap:
| 方法名 | 入参明细 | 使用场景 | 注意事项 |
|---|---|---|---|
ValidateAsync(UpdatePackageInfo, UpdateOptions, CancellationToken) | packageInfo — 更新包信息;options — 更新选项;ct — 取消令牌 | 检查是否有可用的更新 | 返回 UpdateCheckResult,包含 IsUpdateAvailable |
ExecuteUpdateAsync(UpdatePackageInfo, UpdateOptions, CancellationToken) | packageInfo — 更新包信息;options — 更新选项;ct — 取消令牌 | 执行完整更新:下载→校验→安装 | 内置并发保护,重复调用返回 AlreadyInProgress |
Dispose() | 无 | 释放下载器等资源 | — |
CurrentState | 属性(UpdateState) | 查询当前更新状态 | 线程安全(Volatile.Read) |
3.3 回调事件
| 事件名称 | 回调参数 | 触发时机 | 使用说明 |
|---|---|---|---|
AddListenerValidate | ValidateEventArgs — PackageInfo | 版本对比完成,发现可用更新时 | 可用于 UI 展示新版本信息 |
AddListenerDownloadProgressChanged | DownloadProgressChangedEventArgs — PackageInfo, Statistics(DownloadProgressInfo:ProgressPercentage, DownloadedBytes, TotalBytes, BytesPerSecond, RemainingBytes), StatusDescription | 下载进度更新时 | 通过 IProgress<DownloadStatistics> 回调 |
AddListenerUpdateCompleted | UpdateCompletedEventArgs — PackageInfo, Stage(UpdateCompletionStage), PackagePath | 各阶段完成时 | 分为下载完成、校验完成、安装触发、工作流完成四个阶段 |
AddListenerUpdateFailed | UpdateFailedEventArgs — Reason, Message, Exception, PackageInfo | 任何阶段失败时 | 包含结构化的失败原因 |
4. 扩展示例(高阶用法)
4.1 组件可扩展能力总览
所有服务可通过 AddGeneralUpdateMauiAndroid() 注册后,通过 DI 容器替换:
| 接口 | 默认实现 | 说明 |
|---|---|---|
IUpdateDownloader | HttpRangeDownloader | 可恢复 APK 下载 |
IHashValidator | Sha256Validator | SHA256 哈希校验 |
IApkInstaller | AndroidApkInstaller | APK 安装触发 |
IUpdateStorageProvider | UpdateFileStore | 文件路径和存储操作 |
IUpdateLogger | NullUpdateLogger | 日志记录器 |
IUpdateBootstrap | AndroidBootstrap | 更新编排(通过 DI 注册) |
ISslValidationPolicy | 通过 HttpDownloadOptions 配置 | SSL 证书验证策略 |
IHttpAuthProvider | 通过 HttpDownloadOptions 或单包配置 | HTTP 认证提供器 |
4.2 分场景示例
场景 1:DI 容器集成
【场景说明】在 MAUI 应用中将更新服务注册到 DI 容器,便于管理和测试。
using GeneralUpdate.Maui.Android.Abstractions;
using GeneralUpdate.Maui.Android.Models;
using GeneralUpdate.Maui.Android.Services;
using Microsoft.Extensions.Logging;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts => { });
// 注册更新服务
builder.Services.AddGeneralUpdateMauiAndroid();
// 注册应用服务
builder.Services.AddSingleton<MainViewModel>();
builder.Services.AddSingleton<MainPage>();
return builder.Build();
}
}
// 在 ViewModel 中使用
public class MainViewModel
{
private readonly IAndroidBootstrap _bootstrap;
public MainViewModel(IAndroidBootstrap bootstrap)
{
_bootstrap = bootstrap;
WireEvents();
}
public async Task CheckAndUpdateAsync()
{
var package = new UpdatePackageInfo
{
Version = "2.0.0",
DownloadUrl = "https://example.com/app-v2.apk",
Sha256 = "expected-sha256"
};
var options = new UpdateOptions
{
CurrentVersion = "1.0.0",
InstallOptions = new AndroidInstallOptions
{
FileProviderAuthority = "com.myapp.fileprovider"
}
};
var result = await _bootstrap.ExecuteUpdateAsync(package, options, CancellationToken.None);
Console.WriteLine(result.IsSuccess ? "Update succeeded!" : $"Failed: {result.Message}");
}
private void WireEvents()
{
_bootstrap.AddListenerDownloadProgressChanged += (_, args) =>
{
Console.WriteLine($"Progress: {args.Statistics.ProgressPercentage:F1}%");
};
}
}