Skip to content

Commit d82458e

Browse files
JusterZhuclaude
andcommitted
docs: expand GeneralUpdate.Tools Mobile packaging documentation
- Add technical internals: format detection (APK vs AAB), AXML binary parsing (StringPool, StartElement chunks, versionCode extraction), project build pipeline (CsprojParser, dotnet publish, artifact locate) - Add upload form field mapping table with data sources and examples - Add upload service configuration details (endpoint, auth, DPAPI) - Add 5 mobile-specific FAQ entries - Add missing Mobile section to zh-Hans i18n copy - Sync all changes to English i18n Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 21cbed4 commit d82458e

3 files changed

Lines changed: 252 additions & 17 deletions

File tree

website/docs/quickstart/GeneralUpdate.PacketTool.md

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ dotnet run --project GeneralUpdate.Tools.csproj
3030

3131
前往 [GeneralUpdate.Tools Releases](https://github.com/GeneralLibrary/GeneralUpdate.Tools/releases) 下载对应平台的可执行文件,直接运行即可。
3232

33-
> Simulation 模块内部会调用 `dotnet publish` 构建测试应用,因此使用仿真功能时必须安装 .NET SDK仅运行 Patch / Extension / OSS / Config 模块则不需要
33+
> Simulation 模块内部会调用 `dotnet publish` 构建测试应用,因此使用仿真功能时必须安装 .NET SDK。Mobile 模块的项目模式(Build & Locate)也会调用 `dotnet publish`,同样需要 .NET SDK。仅运行 Patch / Extension / OSS / Config 模块以及 Mobile 的文件模式则不需要
3434
3535
## 七个模块速览
3636

@@ -373,12 +373,48 @@ Generate Sample 额外输出:
373373
### 工具内部做了什么
374374

375375
1. **格式检测**:通过文件扩展名(`.apk` / `.aab`)和 ZIP 内部结构(`AndroidManifest.xml` 位置)自动识别包格式。
376-
2. **元数据解析**:使用 `AxmlParser` 从 ZIP 中读取二进制的 `AndroidManifest.xml`,提取 `package``versionName``versionCode`
377-
3. **SHA256 计算**:对完整文件计算 SHA256 哈希值。
378-
4. **文件大小**:读取文件长度并格式化为人类可读的显示(KB/MB/GB)。
379-
5. **项目构建**(仅项目模式):调用 `dotnet publish -c Release -o {publishDir}`,自动定位输出的 APK/AAB 文件。
380-
6. **上传**:通过 HTTP multipart/form-data 将文件和表单字段(Name、Version、Hash、Format、Size、Platform、ProductId、IsForcibly)上传到服务端。
381-
7. **版本记录导出**:上传成功后生成 `mobile_version_{timestamp}.json`,包含完整的版本元数据。
376+
- APK 检测:打开 ZIP 文件,检查根目录是否存在 `AndroidManifest.xml`
377+
- AAB 检测:打开 ZIP 文件,检查是否存在 `base/manifest/AndroidManifest.xml`
378+
- 格式未知时(不是 .apk 也不是 .aab)会直接返回 Unknown。
379+
380+
2. **元数据解析**:使用 `AxmlParser` 解析二进制的 AXML(Android Binary XML)格式,从 ZIP 中读取 `AndroidManifest.xml`。解析流程如下:
381+
- **字符串池提取**:读取 AXML 文件的 Chunk 头,找到类型为 `0x0001` 的 StringPool Chunk,从中解析出所有 UTF-16LE 编码的字符串数组。
382+
- **属性值提取**:遍历 XML 的 Start Element Chunk(类型 `0x0102`),解析属性块(每个属性 20 字节),通过属性名在字符串池中的索引匹配 `package``versionName`,再通过 `rawValueIndex` 从字符串池中取出属性值。
383+
- **versionCode 提取**:versionCode 存储为整型属性(类型 `0x10` = INT_DEC 或 `0x11` = INT_HEX),直接从属性的 `typedValueData` 字段(偏移 +16,4 字节)读取有符号整数。
384+
- AXML 结构与参考:https://justanapplication.wordpress.com/category/android/android-binary-xml/
385+
386+
3. **SHA256 计算**:对完整文件计算 SHA256 哈希值,输出小写十六进制字符串。
387+
388+
4. **文件大小**:读取文件长度并格式化为人类可读的显示(B / KB / MB / GB)。
389+
390+
5. **项目构建**(仅项目模式):选择 `.csproj` 后会触发:
391+
- `MobileCsprojParser.Parse()` 解析 `.csproj` 的 XML,提取 `TargetFramework`(支持单 TFM 和多 TFM,多 TFM 时自动选取包含 `-android` 的目标框架)、`ApplicationId`(映射为 PackageName)、`ApplicationDisplayVersion`(映射为 VersionName)、`ApplicationVersion`(映射为 VersionCode)、`UseMaui`(用于识别 MAUI 项目)、`AndroidPackageFormat``AssemblyName`
392+
- 调用 `dotnet publish "{csprojPath}" -c Release -o "{publishDir}"`
393+
- 构建完成后在 `bin/Release/{tfm}/publish/` 目录搜索 `.apk``.aab` 文件,自动定位构建产物。
394+
- 项目类型显示:MAUI(`<UseMaui>true</UseMaui>`)或 Avalonia(没有 UseMaui)。
395+
396+
6. **上传**:通过 HTTP multipart/form-data 将文件上传到服务端。上传表单字段和对应的数据源如下:
397+
398+
| 字段 | 值来源 | 示例 |
399+
|------|--------|------|
400+
| `Name` | ProductName(用户填写) | `MyApp` |
401+
| `Version` | VersionName(自动解析) | `2.0.0` |
402+
| `Hash` | SHA256(自动计算) | `a1b2c3d4...` |
403+
| `Format` | 包格式(自动识别) | `.apk` / `.aab` |
404+
| `Size` | 文件大小(自动计算) | `50000000` |
405+
| `AppType` | 固定值 `"1"` | `1` |
406+
| `Platform` | Platform(默认 4=Android) | `4` |
407+
| `ProductId` | ProductId(用户填写 GUID) | `2d974e2a-...` |
408+
| `IsForcibly` | 强制更新开关 | `true` / `false` |
409+
410+
上传服务支持以下配置:
411+
- **Server URL**:服务端地址
412+
- **Upload Endpoint**:API 路径,默认 `/Packet/Create`
413+
- **Timeout**:超时时间(秒)
414+
- **Retry Count**:失败重试次数(指数退避)
415+
- **Auth**:认证配置,支持 Basic / Bearer Token / API Key 三种模式(凭据通过 DPAPI 加密存储)
416+
417+
7. **版本记录导出**:上传成功后自动生成 `mobile_version_{timestamp}.json`,包含完整的版本元数据。也可以在不上传的情况下单独点击 **Export Record Only** 导出记录,此时 URL 字段为 `"manual"`
382418

383419
### 输出
384420

@@ -466,6 +502,11 @@ Generate Sample 额外输出:
466502
| Simulation 端口冲突 | 修改 `ServerPort` 或释放本地 5000 端口 |
467503
| 客户端下载后 Hash 校验失败 |**最终上传到 CDN/OSS 的文件**重新计算 Hash,检查是否被中间代理重压缩 |
468504
| Upgrade 进程没有启动 | 检查 `generalupdate.manifest.json``updateAppName``updatePath` 是否与发布目录结构一致 |
505+
| Mobile 分析时提示 "Metadata extraction warning" | AXML 解析未找到预期属性,常见的两种原因:APK 使用资源 ID 引用而非直接文本存储属性值;或 APK 被加固/混淆后 AndroidManifest.xml 结构被修改。可以手动填写 PackageName、VersionName、VersionCode |
506+
| Mobile 项目模式 Build & Locate 失败 | 确认已安装 .NET SDK 且版本支持目标框架(TFM),检查 `.csproj` 包含 `-android` 目标框架,输出目录 `bin/Release/{tfm}/publish/` 没有被写入保护 |
507+
| Mobile 项目模式 "Build output not found" | `dotnet publish` 成功执行但未在预期目录找到 `.apk`/`.aab`。检查 `.csproj``AndroidPackageFormat` 设置是否正确(默认 `aab;apk` 优先产生 APK),以及 TFM 是否自动解析正确 |
508+
| Mobile 上传失败 | 检查服务端地址和 Endpoint 配置是否正确,确认服务端认证方式(Basic / Bearer / API Key)与工具配置一致,查看工具日志中的 HTTP 状态码和错误消息 |
509+
| Mobile 上传后客户端更新失败 | 确认服务端返回的版本记录 JSON 中 `Platform` 字段为 `4`(Android),`Format` 字段与客户端期望的 APK/AAB 格式一致 |
469510

470511
---
471512

website/i18n/en/docusaurus-plugin-content-docs/current/quickstart/GeneralUpdate.PacketTool.md

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ dotnet run --project GeneralUpdate.Tools.csproj
2626

2727
Go to [GeneralUpdate.Tools Releases](https://github.com/GeneralLibrary/GeneralUpdate.Tools/releases) and download the executable for your platform.
2828

29-
> The Simulation module internally runs `dotnet publish` to build test apps, so you need the .NET SDK for that feature. Patch / Extension / OSS / Config / Mobile modules work without the SDK. However, Mobile's Project Mode (Build & Locate) does require the .NET SDK.
29+
> The Simulation module internally runs `dotnet publish` to build test apps, so you need the .NET SDK for that feature. The Mobile module's Project Mode (Build & Locate) also runs `dotnet publish`, which requires the .NET SDK too. Patch / Extension / OSS / Config modules and Mobile's File Mode work without the SDK.
3030
3131
## Seven modules at a glance
3232

@@ -353,12 +353,48 @@ Supports two modes:
353353
### What the tool does internally
354354

355355
1. **Format detection**: Identifies package format via file extension (`.apk` / `.aab`) and ZIP internal structure (AndroidManifest.xml location).
356-
2. **Metadata parsing**: Uses `AxmlParser` to read binary `AndroidManifest.xml` from the ZIP, extracting `package`, `versionName`, `versionCode`.
357-
3. **SHA256 computation**: Computes SHA256 hash of the full file.
358-
4. **File size**: Reads file length and formats it for human-readable display (KB/MB/GB).
359-
5. **Project build** (Project mode only): Runs `dotnet publish -c Release -o {publishDir}`, then auto-locates the output APK/AAB.
360-
6. **Upload**: Sends file and form fields (Name, Version, Hash, Format, Size, Platform, ProductId, IsForcibly) via HTTP multipart/form-data.
361-
7. **Version record export**: Generates `mobile_version_{timestamp}.json` with full version metadata after successful upload.
356+
- APK detection: Opens the ZIP file and checks for `AndroidManifest.xml` at the root.
357+
- AAB detection: Opens the ZIP file and checks for `base/manifest/AndroidManifest.xml`.
358+
- If the format is neither `.apk` nor `.aab`, the detector returns Unknown.
359+
360+
2. **Metadata parsing**: Uses `AxmlParser` to parse the binary AXML (Android Binary XML) format from the ZIP's `AndroidManifest.xml`. The parsing process works as follows:
361+
- **String pool extraction**: Reads AXML chunk headers, locates the StringPool chunk (type `0x0001`), and extracts all UTF-16LE encoded strings.
362+
- **Attribute value extraction**: Walks through Start Element chunks (type `0x0102`), parses the attribute block (20 bytes per attribute), matches attribute names by their string pool index to find `package` and `versionName`, then resolves values via `rawValueIndex` from the string pool.
363+
- **versionCode extraction**: versionCode is stored as a typed integer attribute (type `0x10` = INT_DEC or `0x11` = INT_HEX), read directly from the `typedValueData` field (offset +16, 4 bytes) as a signed integer.
364+
- AXML chunk structure reference: https://justanapplication.wordpress.com/category/android/android-binary-xml/
365+
366+
3. **SHA256 computation**: Computes SHA256 hash of the full file, output as a lowercase hex string.
367+
368+
4. **File size**: Reads file length and formats it for human-readable display (B / KB / MB / GB).
369+
370+
5. **Project build** (Project mode only): Selecting a `.csproj` triggers:
371+
- `MobileCsprojParser.Parse()` reads the `.csproj` XML to extract `TargetFramework` (supports single and multi-TFM; auto-selects the one containing `-android`), `ApplicationId` (mapped to PackageName), `ApplicationDisplayVersion` (mapped to VersionName), `ApplicationVersion` (mapped to VersionCode), `UseMaui` (identifies MAUI projects), `AndroidPackageFormat`, and `AssemblyName`.
372+
- Runs `dotnet publish "{csprojPath}" -c Release -o "{publishDir}"`.
373+
- After build, searches `bin/Release/{tfm}/publish/` for `.apk` or `.aab` files, auto-locating the build artifact.
374+
- Project type display: MAUI (`<UseMaui>true</UseMaui>`) or Avalonia (no UseMaui).
375+
376+
6. **Upload**: Sends the file and form fields via HTTP multipart/form-data. The form fields and their data sources are:
377+
378+
| Field | Source | Example |
379+
|-------|--------|---------|
380+
| `Name` | ProductName (user input) | `MyApp` |
381+
| `Version` | VersionName (auto-parsed) | `2.0.0` |
382+
| `Hash` | SHA256 (auto-computed) | `a1b2c3d4...` |
383+
| `Format` | Package format (auto-detected) | `.apk` / `.aab` |
384+
| `Size` | File size (auto-computed) | `50000000` |
385+
| `AppType` | Fixed value `"1"` | `1` |
386+
| `Platform` | Platform field (default 4=Android) | `4` |
387+
| `ProductId` | ProductId (user-entered GUID) | `2d974e2a-...` |
388+
| `IsForcibly` | Force update toggle | `true` / `false` |
389+
390+
The upload service supports the following configuration:
391+
- **Server URL**: Server base address
392+
- **Upload Endpoint**: API path, defaults to `/Packet/Create`
393+
- **Timeout**: Timeout in seconds
394+
- **Retry Count**: Retry attempts on failure (exponential backoff)
395+
- **Auth**: Authentication configuration, supports Basic / Bearer Token / API Key modes (credentials stored encrypted via DPAPI)
396+
397+
7. **Version record export**: After a successful upload, generates `mobile_version_{timestamp}.json` with full version metadata. You can also use **Export Record Only** to generate the record without uploading — the URL field will be `"manual"`.
362398

363399
### Output
364400

@@ -447,6 +483,11 @@ Use the Mobile module for Android app releases:
447483
| Simulation port conflict | Change `ServerPort` or free up local port 5000 |
448484
| Hash mismatch after client download | Re-compute hash on the file that was actually uploaded to CDN/OSS; check for proxy re-compression |
449485
| Upgrade process doesn't start | Verify `updateAppName` and `updatePath` in `generalupdate.manifest.json` match the publish directory structure |
486+
| Mobile analysis shows "Metadata extraction warning" | AXML parser could not find the expected attributes. Common causes: the APK uses resource ID references instead of direct string values; or the APK has been packed/obfuscated and the AndroidManifest.xml structure was modified. You can fill in PackageName, VersionName, and VersionCode manually |
487+
| Mobile Project Mode Build & Locate fails | Verify that the .NET SDK is installed and supports the target framework. Ensure the `.csproj` contains an `-android` target framework. Make sure the output directory `bin/Release/{tfm}/publish/` is not write-protected |
488+
| Mobile Project Mode "Build output not found" | `dotnet publish` succeeded but no `.apk`/`.aab` was found in the expected directory. Check the `AndroidPackageFormat` setting in `.csproj` (default `aab;apk` produces APK first), and verify that the TFM was resolved correctly |
489+
| Mobile upload fails | Check that the server URL and endpoint path are configured correctly. Verify the server authentication method (Basic / Bearer / API Key) matches the tool configuration. Review the tool logs for the HTTP status code and error message |
490+
| Mobile client update fails after upload | Confirm that the version record JSON returned by the server has `Platform` set to `4` (Android), and the `Format` field matches the APK/AAB format the client expects |
450491

451492
---
452493

0 commit comments

Comments
 (0)