Skip to content

Commit 4bc7862

Browse files
CopilotJusterZhu
andcommitted
docs: add bilingual README for GeneralUpdate.Maui.Android
Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> Agent-Logs-Url: https://github.com/GeneralLibrary/GeneralUpdate.Maui/sessions/c7996fc9-35ee-4c1a-94b8-40a44c3d22df
1 parent 126148b commit 4bc7862

2 files changed

Lines changed: 250 additions & 0 deletions

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# GeneralUpdate.Maui.Android
2+
3+
[中文文档 (README.zh-CN.md)](./README.zh-CN.md)
4+
5+
UI-less Android auto-update core for .NET MAUI, focused on reusable update orchestration:
6+
7+
- update discovery/validation
8+
- resumable APK download (HTTP Range)
9+
- SHA256 integrity verification
10+
- Android installer triggering (`FileProvider` + system installer intent)
11+
- lifecycle/status event notifications
12+
13+
> Target frameworks: `net10.0;net10.0-android`
14+
> C# language version: `latest`
15+
16+
## Installation
17+
18+
Reference the project/package in your MAUI app and configure Android `FileProvider` authority.
19+
20+
## Quick Start
21+
22+
```csharp
23+
using GeneralUpdate.Maui.Android.Models;
24+
using GeneralUpdate.Maui.Android.Services;
25+
26+
var bootstrap = GeneralUpdateBootstrap.CreateDefault();
27+
28+
bootstrap.AddListenerValidate += (_, e) =>
29+
{
30+
Console.WriteLine($"New version: {e.PackageInfo.Version}");
31+
};
32+
33+
bootstrap.AddListenerDownloadProgressChanged += (_, e) =>
34+
{
35+
var s = e.Statistics;
36+
Console.WriteLine(
37+
$"{s.ProgressPercentage:F2}% | {s.DownloadedBytes}/{s.TotalBytes} | " +
38+
$"remaining: {s.RemainingBytes} | speed: {s.BytesPerSecond:F0} B/s");
39+
};
40+
41+
bootstrap.AddListenerUpdateCompleted += (_, e) =>
42+
{
43+
Console.WriteLine($"Stage={e.Stage}, File={e.PackagePath}");
44+
};
45+
46+
bootstrap.AddListenerUpdateFailed += (_, e) =>
47+
{
48+
Console.WriteLine($"Failed: {e.Reason}, {e.Message}");
49+
};
50+
51+
var package = new UpdatePackageInfo
52+
{
53+
Version = "2.0.0",
54+
VersionName = "2.0",
55+
ReleaseNotes = "Performance and stability improvements",
56+
DownloadUrl = "https://example.com/app-release.apk",
57+
Sha256 = "3A0D...F9C2",
58+
PackageSize = 52_428_800
59+
};
60+
61+
var options = new UpdateOptions
62+
{
63+
CurrentVersion = "1.5.0",
64+
InstallOptions = new AndroidInstallOptions
65+
{
66+
FileProviderAuthority = $"{AppInfo.PackageName}.fileprovider"
67+
}
68+
};
69+
70+
var check = await bootstrap.ValidateAsync(package, options, CancellationToken.None);
71+
if (check.IsUpdateAvailable)
72+
{
73+
var result = await bootstrap.ExecuteUpdateAsync(package, options, CancellationToken.None);
74+
Console.WriteLine(result.IsSuccess ? "Update workflow completed." : $"Update failed: {result.Message}");
75+
}
76+
```
77+
78+
## Event Model
79+
80+
`IAndroidBootstrap` exposes:
81+
82+
- `AddListenerValidate`: raised when a higher version is validated.
83+
- `AddListenerDownloadProgressChanged`: periodic statistics (`BytesPerSecond`, `DownloadedBytes`, `RemainingBytes`, `TotalBytes`, `ProgressPercentage`) and status.
84+
- `AddListenerUpdateCompleted`: workflow milestones:
85+
- `DownloadCompleted`
86+
- `VerificationCompleted`
87+
- `InstallationTriggered`
88+
- `WorkflowCompleted`
89+
- `AddListenerUpdateFailed`: typed failure reason + message + exception.
90+
91+
## Workflow States
92+
93+
`UpdateState` includes:
94+
95+
`None`, `Checking`, `UpdateAvailable`, `Downloading`, `Verifying`, `ReadyToInstall`, `Installing`, `Completed`, `Failed`, `Canceled`.
96+
97+
## Thread-Safety and Execution Guarantees
98+
99+
- only one `ExecuteUpdateAsync` can run at a time per bootstrap instance
100+
- state transitions are atomic (`CurrentState` is thread-safe to read)
101+
- listener exceptions are isolated and logged, and do not stop workflow execution
102+
- cancellation is honored across validation/download/verification/install trigger stages
103+
104+
## Android Requirements
105+
106+
1. Configure `FileProvider` in `AndroidManifest.xml`.
107+
2. Provide a matching authority in `AndroidInstallOptions.FileProviderAuthority`.
108+
3. For Android 8+, ensure app is allowed to install unknown apps (`CanRequestPackageInstalls()`).
109+
110+
Template files are included in this project:
111+
112+
- `Platforms/Android/AndroidManifest.xml`
113+
- `Platforms/Android/XML/provider_paths.xml`
114+
115+
## Testing
116+
117+
Run updater tests with:
118+
119+
```bash
120+
dotnet test src/GeneralUpdate.Maui.Android.Tests/GeneralUpdate.Maui.Android.Tests.csproj -p:TargetFramework=net10.0 -p:TargetFrameworks=net10.0
121+
```
122+
123+
## License
124+
125+
See repository [LICENSE](../../LICENSE).
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# GeneralUpdate.Maui.Android
2+
3+
[English README](./README.md)
4+
5+
面向 .NET MAUI 的 **无 UI** Android 自动更新核心组件,强调可复用、低耦合的更新编排能力:
6+
7+
- 更新发现与校验
8+
- 支持断点续传的 APK 下载(HTTP Range)
9+
- SHA256 完整性校验
10+
- Android 安装触发(`FileProvider` + 系统安装器 Intent)
11+
- 生命周期与状态事件通知
12+
13+
> 目标框架:`net10.0;net10.0-android`
14+
> C# 语言版本:`latest`
15+
16+
## 安装与接入
17+
18+
在 MAUI 应用中引用该项目/包,并配置 Android `FileProvider` authority。
19+
20+
## 快速开始
21+
22+
```csharp
23+
using GeneralUpdate.Maui.Android.Models;
24+
using GeneralUpdate.Maui.Android.Services;
25+
26+
var bootstrap = GeneralUpdateBootstrap.CreateDefault();
27+
28+
bootstrap.AddListenerValidate += (_, e) =>
29+
{
30+
Console.WriteLine($"发现新版本: {e.PackageInfo.Version}");
31+
};
32+
33+
bootstrap.AddListenerDownloadProgressChanged += (_, e) =>
34+
{
35+
var s = e.Statistics;
36+
Console.WriteLine(
37+
$"{s.ProgressPercentage:F2}% | {s.DownloadedBytes}/{s.TotalBytes} | " +
38+
$"剩余: {s.RemainingBytes} | 速度: {s.BytesPerSecond:F0} B/s");
39+
};
40+
41+
bootstrap.AddListenerUpdateCompleted += (_, e) =>
42+
{
43+
Console.WriteLine($"阶段={e.Stage}, 文件={e.PackagePath}");
44+
};
45+
46+
bootstrap.AddListenerUpdateFailed += (_, e) =>
47+
{
48+
Console.WriteLine($"失败: {e.Reason}, {e.Message}");
49+
};
50+
51+
var package = new UpdatePackageInfo
52+
{
53+
Version = "2.0.0",
54+
VersionName = "2.0",
55+
ReleaseNotes = "Performance and stability improvements",
56+
DownloadUrl = "https://example.com/app-release.apk",
57+
Sha256 = "3A0D...F9C2",
58+
PackageSize = 52_428_800
59+
};
60+
61+
var options = new UpdateOptions
62+
{
63+
CurrentVersion = "1.5.0",
64+
InstallOptions = new AndroidInstallOptions
65+
{
66+
FileProviderAuthority = $"{AppInfo.PackageName}.fileprovider"
67+
}
68+
};
69+
70+
var check = await bootstrap.ValidateAsync(package, options, CancellationToken.None);
71+
if (check.IsUpdateAvailable)
72+
{
73+
var result = await bootstrap.ExecuteUpdateAsync(package, options, CancellationToken.None);
74+
Console.WriteLine(result.IsSuccess ? "更新流程完成。" : $"更新失败: {result.Message}");
75+
}
76+
```
77+
78+
## 事件模型
79+
80+
`IAndroidBootstrap` 暴露以下事件:
81+
82+
- `AddListenerValidate`:检测到更高版本时触发。
83+
- `AddListenerDownloadProgressChanged`:周期性上报下载统计(`BytesPerSecond``DownloadedBytes``RemainingBytes``TotalBytes``ProgressPercentage`)及状态描述。
84+
- `AddListenerUpdateCompleted`:更新流程里程碑事件:
85+
- `DownloadCompleted`
86+
- `VerificationCompleted`
87+
- `InstallationTriggered`
88+
- `WorkflowCompleted`
89+
- `AddListenerUpdateFailed`:失败原因、消息、异常信息。
90+
91+
## 流程状态
92+
93+
`UpdateState` 包含:
94+
95+
`None``Checking``UpdateAvailable``Downloading``Verifying``ReadyToInstall``Installing``Completed``Failed``Canceled`
96+
97+
## 线程安全与执行保障
98+
99+
- 同一个 bootstrap 实例一次仅允许一个 `ExecuteUpdateAsync` 执行
100+
- 状态切换为原子操作(`CurrentState` 可线程安全读取)
101+
- 事件监听器异常会被隔离并记录日志,不会中断主流程
102+
- 支持从校验/下载/验签/触发安装全过程的取消传播
103+
104+
## Android 平台要求
105+
106+
1.`AndroidManifest.xml` 中配置 `FileProvider`
107+
2. `AndroidInstallOptions.FileProviderAuthority` 必须与 manifest 中配置一致。
108+
3. Android 8+ 需允许“安装未知应用”(可通过 `CanRequestPackageInstalls()` 检测)。
109+
110+
项目内包含 Android 模板文件:
111+
112+
- `Platforms/Android/AndroidManifest.xml`
113+
- `Platforms/Android/XML/provider_paths.xml`
114+
115+
## 测试
116+
117+
建议使用以下命令运行更新器测试:
118+
119+
```bash
120+
dotnet test src/GeneralUpdate.Maui.Android.Tests/GeneralUpdate.Maui.Android.Tests.csproj -p:TargetFramework=net10.0 -p:TargetFrameworks=net10.0
121+
```
122+
123+
## 许可证
124+
125+
参见仓库根目录 [LICENSE](../../LICENSE)

0 commit comments

Comments
 (0)