docs: 优化客户端文档入口和部署说明
This commit is contained in:
@@ -0,0 +1,407 @@
|
||||
# UpdateClientSDK 客户端接入、打包和部署指南
|
||||
|
||||
本文按“维护者打包 SDK -> 你接入业务软件 -> 联调测试 -> 生成最终客户端包”的顺序说明。你拿到这份文档后,按章节一步一步做即可。
|
||||
|
||||
## 先看这里:你要做哪件事
|
||||
|
||||
| 你的目标 | 直接看哪一节 |
|
||||
| --- | --- |
|
||||
| 重新生成给别人用的 SDK 包 | 二、维护者:生成 SDK 包 |
|
||||
| 把 SDK 放到 SimCAE 或其他业务软件目录 | 三、你:把 SDK 放进业务软件目录 |
|
||||
| 从后台生成 `app_config.json` | 四、你:生成并填写 app_config.json |
|
||||
| 给业务主程序接入启动保护代码 | 五、你:业务主程序接入要求 |
|
||||
| 验证升级、回滚、健康检查 | 六、你:联调测试 |
|
||||
| 生成最终交付给用户的客户端包 | 七、维护者:生成最终客户端包 |
|
||||
|
||||
## 一、这个 SDK 是什么
|
||||
|
||||
UpdateClientSDK 是“独立更新器 SDK / 升级运行时 SDK”。它不是传统的 `include + lib` 形态,而是把自动升级能力做成一组独立程序,让业务软件通过这些程序完成检查更新、下载、安装、回滚和启动保护。
|
||||
|
||||
SDK 核心程序:
|
||||
|
||||
- `Launcher.exe` / `Launcher`:用户入口。检查版本、验证授权和策略,决定直接启动业务主程序或进入升级流程。
|
||||
- `Updater.exe` / `Updater`:下载、校验、备份、安装、健康确认、提交或回滚。
|
||||
- `Bootstrap.exe` / `Bootstrap`:处理运行中可能被占用的 EXE/DLL 或 Linux 可执行文件替换。
|
||||
- `config/app_config.json`:部署配置源文件。启动时会同步到当前用户的 QSettings 配置区;Windows 下对应注册表,Linux 下对应用户配置文件。
|
||||
- `config/manifest_public_key.pem`:Manifest 签名公钥,用来验证服务端发布包没有被篡改。
|
||||
|
||||
## 二、维护者:生成 SDK 包
|
||||
|
||||
这一节是 SDK 维护者操作。接入方通常只需要拿到 `UpdateClientSDK.zip`。
|
||||
|
||||
打包前确认:
|
||||
|
||||
1. 已在 Windows 上用 Release 配置编译完成,输出目录里有 `Launcher.exe`、`Updater.exe`、`Bootstrap.exe`。
|
||||
2. `config/manifest_public_key.pem` 和服务端使用的私钥是一对。
|
||||
3. SDK Word 接入说明已经放在 `update-client` 根目录或 `update-client/Docs` 目录下,文件名包含 `SDK`,例如 `SimCAE自动升级SDK接入说明_v0.1.docx`。打包脚本会把它复制到 SDK 根目录,方便接入方一打开压缩包就能看到。
|
||||
4. 如果业务软件本身已经带 Qt DLL,通常不要把 SDK 的 Qt 运行库打进去,避免 Qt 版本混用。
|
||||
|
||||
在 Windows PowerShell 中执行:
|
||||
|
||||
```powershell
|
||||
cd C:\Users\admin\Desktop\update-client
|
||||
|
||||
.\scripts\package-sdk.ps1 `
|
||||
-SourceDir .\out\bin `
|
||||
-OutputDir .\dist\UpdateClientSDK `
|
||||
-ZipFile .\dist\UpdateClientSDK.zip `
|
||||
-SdkVersion 0.1.0
|
||||
```
|
||||
|
||||
生成结果:
|
||||
|
||||
```text
|
||||
dist/
|
||||
UpdateClientSDK/
|
||||
SimCAE自动升级SDK接入说明_v0.1.docx
|
||||
sdk_manifest.json
|
||||
bin/
|
||||
Launcher.exe
|
||||
Updater.exe
|
||||
Bootstrap.exe
|
||||
...
|
||||
config/
|
||||
app_config.json
|
||||
manifest_public_key.pem
|
||||
scripts/
|
||||
install-sdk.ps1
|
||||
package-client.ps1
|
||||
package-sdk.ps1
|
||||
UpdateClientSDK.zip
|
||||
```
|
||||
|
||||
把 `dist/UpdateClientSDK.zip` 发给接入方即可。
|
||||
|
||||
可选参数:
|
||||
|
||||
- `-IncludeDemoMainApp`:把仓库里的 Demo 主程序 `MainApp.exe` 也打进 SDK,方便演示。
|
||||
- `-IncludeQtRuntime`:把 Qt 运行库也打进 SDK。只有业务软件本身不带 Qt 时才建议使用。
|
||||
|
||||
Linux SDK 打包方式:
|
||||
|
||||
```bash
|
||||
cd /home/laluo/project/update-client
|
||||
|
||||
cmake --preset linux-x64-release
|
||||
cmake --build --preset linux-x64-release
|
||||
|
||||
bash ./scripts/package-sdk.sh \
|
||||
--source-dir ./out/linux/bin \
|
||||
--output-dir ./dist/UpdateClientSDK-linux \
|
||||
--archive ./dist/UpdateClientSDK-linux.tar.gz \
|
||||
--sdk-version 0.1.0
|
||||
```
|
||||
|
||||
Linux SDK 包里核心程序名不带 `.exe`:
|
||||
|
||||
```text
|
||||
dist/
|
||||
UpdateClientSDK-linux/
|
||||
SimCAE自动升级SDK接入说明_v0.1.docx
|
||||
sdk_manifest.json
|
||||
bin/
|
||||
Launcher
|
||||
Updater
|
||||
Bootstrap
|
||||
Common/
|
||||
ConfigHelper.h
|
||||
ConfigHelper.cpp
|
||||
TicketHelper.h
|
||||
TicketHelper.cpp
|
||||
config/
|
||||
app_config.json
|
||||
manifest_public_key.pem
|
||||
scripts/
|
||||
package-sdk.sh
|
||||
package-client.sh
|
||||
UpdateClientSDK-linux.tar.gz
|
||||
```
|
||||
|
||||
## 三、你:把 SDK 放进业务软件目录
|
||||
|
||||
假设业务软件目录是:
|
||||
|
||||
```text
|
||||
D:\SimCAE\
|
||||
bin\
|
||||
SimCAE.exe
|
||||
Qt5Core.dll
|
||||
...
|
||||
Licenses\
|
||||
installerResources\
|
||||
```
|
||||
|
||||
推荐把 SDK 放到 `bin` 目录,和 `SimCAE.exe` 同级;后台发布新版本时仍选择整个 `D:\SimCAE\` 作为发布根目录。
|
||||
|
||||
先解压 SDK:
|
||||
|
||||
```powershell
|
||||
Expand-Archive D:\交付\UpdateClientSDK.zip -DestinationPath D:\SimCAE_SDK -Force
|
||||
```
|
||||
|
||||
再安装到业务软件的 `bin` 目录:
|
||||
|
||||
```powershell
|
||||
cd D:\SimCAE\bin
|
||||
|
||||
D:\SimCAE_SDK\scripts\install-sdk.ps1 `
|
||||
-SdkRoot D:\SimCAE_SDK `
|
||||
-ReleaseDir .
|
||||
```
|
||||
|
||||
安装后目录应类似:
|
||||
|
||||
```text
|
||||
D:\SimCAE\
|
||||
bin\
|
||||
Launcher.exe
|
||||
Updater.exe
|
||||
Bootstrap.exe
|
||||
SimCAE.exe
|
||||
config\
|
||||
app_config.json
|
||||
manifest_public_key.pem
|
||||
Qt5Core.dll
|
||||
...
|
||||
Licenses\
|
||||
installerResources\
|
||||
```
|
||||
|
||||
如果你需要重新覆盖 `config/app_config.json`,执行安装脚本时加 `-OverwriteConfig`:
|
||||
|
||||
```powershell
|
||||
D:\SimCAE_SDK\scripts\install-sdk.ps1 `
|
||||
-SdkRoot D:\SimCAE_SDK `
|
||||
-ReleaseDir D:\SimCAE\bin `
|
||||
-OverwriteConfig
|
||||
```
|
||||
|
||||
注意:SimCAE 自己已经带有 Qt 运行库。SDK 的 Launcher/Updater 应复用 SimCAE 的 `Qt5*.dll`、`platforms/`、`imageformats/` 等目录。不要把另一套 Qt DLL 覆盖到 `SimCAE\bin`,否则可能出现“无法定位程序输入点”一类错误。
|
||||
|
||||
## 四、你:生成并填写 app_config.json
|
||||
|
||||
最推荐的方式是在服务端管理后台生成客户端配置:
|
||||
|
||||
1. 浏览器打开服务端管理后台,例如 `http://服务器IP:8000/`。
|
||||
2. 登录后台。
|
||||
3. 创建或选择应用,例如 `app_id=simcae`。
|
||||
4. 创建 License。
|
||||
5. 在“客户端配置生成”区域选择应用、渠道、License 和主程序名。
|
||||
6. 点击生成配置。
|
||||
7. 复制生成的 JSON,覆盖 `D:\SimCAE\bin\config\app_config.json`。
|
||||
|
||||
配置同步规则:
|
||||
|
||||
- `app_config.json` 是部署配置源文件,适合交付、复制、人工修改。
|
||||
- Launcher / Updater / MainApp 启动时会计算 `app_config.json` 解析后的 JSON 内容 SHA256;如果 JSON 内容和上次导入时不同,就把文件里的配置重新写入当前 Windows 用户的注册表。
|
||||
- 后续运行时优先从注册表读取配置,不再每次直接读 JSON。
|
||||
- 运行过程中产生的动态值,例如首次输入的 `license_key`、服务端返回的 `device_id`、升级后的 `current_version`,会写入注册表。
|
||||
- 为减少明文暴露,SDK 成功把非空 `app_config.json` 导入注册表后,会把 `app_config.json` 内容自动清空为 `{}`,但不会删除这个文件。以后你从管理后台复制新的客户端配置时,直接覆盖这个文件即可。
|
||||
- SDK 会同步更新注册表里的 `source_sha256`,所以 `{}` 不会在下一次启动时反向覆盖注册表配置。
|
||||
- 如果你手动修改了 `app_config.json`,下一次启动会重新导入并覆盖注册表里的同名字段。
|
||||
- 如果检测到 `app_config.json` 确实发生变化,SDK 会同时删除 `config/client_identity.dat`、`config/version_policy.dat` 和 `config/local_state.json`,避免继续使用旧 License、旧设备身份、旧版本策略或旧防回滚状态;如果安装目录不可写,会弹出管理员权限确认框。
|
||||
- 正常启动成功后,不要删除 `client_identity.dat`、`version_policy.dat`、`local_state.json`。它们分别用于本地设备身份、离线策略和防回滚/防时间倒退,删除后会影响离线启动或导致重新授权。
|
||||
- 注册表按安装目录隔离;同一台电脑上多个安装目录不会互相覆盖配置。
|
||||
- 注册表位置为 `HKEY_CURRENT_USER\Software\Marsco\UpdateClientSDK\installations\<安装目录SHA256>\config`。
|
||||
|
||||
关键字段说明:
|
||||
|
||||
- `app_id`:服务端应用 ID,要和管理后台里的应用一致。
|
||||
- `app_name`:应用显示名称。
|
||||
- `channel`:发布渠道,例如 `stable`、`beta`、`dev`。
|
||||
- `current_version`:客户端当前初始版本,必须和后台已发布的版本一致。
|
||||
- `client_protocol`:客户端协议号,当前建议为 `3`。
|
||||
- `launch_token`:本机启动票据 HMAC 密钥。服务端生成配置时会填默认值;正式部署建议按项目统一修改。
|
||||
- `license_key`:管理后台创建 License 后生成的授权码。为空时首次启动 `Launcher.exe` 会弹窗让用户输入并保存到注册表;如果授权错误或过期,也会提示重新输入。
|
||||
- `api_base_url`:服务端 API 地址,例如 `http://192.168.229.128:8000`。
|
||||
- `client_token`:服务端 `.env` 中的 `CLIENT_API_TOKEN`,必须和服务端一致。
|
||||
- `device_id`:设备 ID。一般可以留空,首次启动时 SDK 会向服务端登记并写入注册表。
|
||||
- `install_root`:被更新的安装根目录相对 `Launcher.exe` 所在目录的位置。SDK 放在 `bin` 时填 `..`。
|
||||
- `main_executable`:业务主程序相对 `Launcher.exe` 所在目录的路径。SDK 放在 `bin` 且主程序也在 `bin` 时填 `SimCAE.exe`。
|
||||
- `launcher_executable`、`updater_executable`、`bootstrap_executable`:通常不用改。
|
||||
- `platform`、`arch`:当前为 `windows`、`x64`。
|
||||
|
||||
典型配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"app_id": "simcae",
|
||||
"app_name": "SimCAE",
|
||||
"channel": "stable",
|
||||
"current_version": "1.0.0",
|
||||
"client_protocol": "3",
|
||||
"launch_token": "SimCAE_Launch_Token_2026_ChangeMe_32Bytes",
|
||||
"license_key": "MARSCO-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"api_base_url": "http://192.168.229.128:8000",
|
||||
"client_token": "SimCAEClientToken2026",
|
||||
"request_timeout_ms": "5000",
|
||||
"temp_folder": "update_temp",
|
||||
"device_id": "",
|
||||
"install_root": "..",
|
||||
"main_executable": "SimCAE.exe",
|
||||
"launcher_executable": "Launcher.exe",
|
||||
"updater_executable": "Updater.exe",
|
||||
"bootstrap_executable": "Bootstrap.exe",
|
||||
"health_check_timeout_ms": "15000",
|
||||
"platform": "windows",
|
||||
"arch": "x64"
|
||||
}
|
||||
```
|
||||
|
||||
## 五、你:业务主程序需要配合什么
|
||||
|
||||
当前安全模式下,业务主程序需要配合两件事:
|
||||
|
||||
1. 接收 `--ticket-file=<path>` 参数,验证并消费一次性启动票据。
|
||||
2. 如果收到 `--health-file=<path>` 参数,启动成功后向该路径写入 `ok\n`,让 Updater 确认新版本可用。
|
||||
|
||||
接入位置:
|
||||
|
||||
```text
|
||||
main / WinMain 开头,创建主窗口之前
|
||||
```
|
||||
|
||||
当前仓库里的 `update-client/MainApp/main.cpp` 是接入示例,已经实现:
|
||||
|
||||
- 启动票据校验。
|
||||
- 本地 License/设备身份校验。
|
||||
- 本地策略校验。
|
||||
- Manifest 完整性校验。
|
||||
- 健康标记写入。
|
||||
|
||||
真正接入业务软件时,把这些启动检查逻辑移植到业务主程序。用户入口应改成 `Launcher.exe`,不要让用户直接双击 `SimCAE.exe`。
|
||||
|
||||
重要:业务主程序校验 ticket 时,必须使用 SDK 当前运行配置里的动态值,不要直接从 `app_config.json` 读取 `device_id`。
|
||||
|
||||
原因是 `app_config.json` 是部署源文件,网页生成时 `device_id` 通常为空;真正的设备 ID 是 `Launcher.exe` 首次向服务端登记后写入当前用户注册表的。`Launcher.exe` 生成 ticket 时使用的是注册表里的真实 `device_id`。如果业务主程序从 `app_config.json` 读取空的 `device_id` 来校验,就会出现:
|
||||
|
||||
```text
|
||||
ticket signature, identity, time or nonce invalid
|
||||
```
|
||||
|
||||
或者细化后的:
|
||||
|
||||
```text
|
||||
ticket device_id mismatch
|
||||
```
|
||||
|
||||
业务主程序应像 `MainApp/main.cpp` 示例一样使用:
|
||||
|
||||
```cpp
|
||||
ConfigHelper& config = ConfigHelper::instance();
|
||||
TicketHelper::consumeAndVerify(
|
||||
ticketFilePath,
|
||||
config.getValue("App", "app_id"),
|
||||
config.getValue("Update", "device_id"),
|
||||
config.getValue("App", "current_version"),
|
||||
config.getValue("App", "launch_token"),
|
||||
&ticketError);
|
||||
```
|
||||
|
||||
也就是说,接入业务主程序时不能只复制一小段 ticket 代码后自己解析 JSON;要么复用 SDK 的 `ConfigHelper` / `TicketHelper`,要么保证业务主程序读取到的 `app_id`、`device_id`、`current_version`、`launch_token` 和 `Launcher.exe` 完全来自同一套运行配置。
|
||||
|
||||
## 六、你:准备服务端数据
|
||||
|
||||
首次联调前,服务端至少要准备这些内容:
|
||||
|
||||
1. 创建应用,例如 `simcae`。
|
||||
2. 创建渠道,例如 `stable`。
|
||||
3. 创建 License。
|
||||
4. 发布一个初始版本,例如 `1.0.0`。
|
||||
5. 生成客户端配置,并写入 `bin\config\app_config.json`。客户端下次启动时会自动同步到注册表。
|
||||
|
||||
为什么必须先发布初始版本:Launcher 启动业务主程序前会做 Manifest 完整性校验。这个 Manifest 是服务端发布版本时生成并签名的清单,用来证明当前本地文件属于一个可信版本。如果没有发布过 `current_version` 对应版本,客户端会提示签名 Manifest 缓存缺失。
|
||||
|
||||
后台发布版本时,选择整个安装根目录,例如 `D:\SimCAE\`,不要只选择 `D:\SimCAE\bin`。这样服务端会把 `bin/SimCAE.exe`、`Licenses/`、`installerResources/` 等完整结构写进 Manifest。
|
||||
|
||||
## 七、你:运行和联调
|
||||
|
||||
基础联调步骤:
|
||||
|
||||
1. 确认服务端正在运行。
|
||||
2. 确认 `bin\config\app_config.json` 中 `api_base_url`、`client_token`、`license_key`、`current_version` 正确。
|
||||
3. 双击 `bin\Launcher.exe`。
|
||||
4. 首次启动时如果 `license_key` 为空,按弹窗输入后台创建的 License;SDK 会把它保存到注册表。
|
||||
5. 成功进入业务主程序后,回到后台查看设备、升级日志、下载日志。
|
||||
6. 在后台发布更高版本,例如从 `1.0.0` 发布到 `1.0.1`。
|
||||
7. 再次启动 `Launcher.exe`,验证升级、健康确认和回滚逻辑。
|
||||
|
||||
联调目录建议:
|
||||
|
||||
```text
|
||||
D:\SimCAE_Release\
|
||||
C:\Users\<你的用户名>\Desktop\SimCAE_Release\
|
||||
```
|
||||
|
||||
如果安装在 `C:\Program Files\...` 这类默认不可写目录,普通配置值会写入当前用户注册表,不需要修改 `app_config.json`。但 `client_identity.dat`、`local_state.json`、`version_policy.dat` 等本地状态文件仍位于安装目录下;当这些文件需要写入且目录不可写时,SDK 会弹出 Windows 管理员权限确认框,用户点击“是”后会继续保存。
|
||||
|
||||
注意:这次提权主要覆盖小型配置/状态文件的写入和删除。更新缓存、离线包暂存、升级替换 EXE/DLL 等大文件操作仍建议放在可写目录;如果最终产品必须完整安装到 `C:\Program Files\SimCAE\bin` 并在普通用户下自动升级,后续建议把运行时状态迁移到 `ProgramData` / `AppData`,或让 Updater/Bootstrap 在替换安装目录文件时走管理员权限。
|
||||
|
||||
## 八、维护者:生成某个产品的最终客户端包
|
||||
|
||||
SDK 是给接入方开发使用的。最终给用户安装或分发时,可以从已经联调过的 Release 目录生成最终客户端包。
|
||||
|
||||
在 Windows PowerShell 中执行:
|
||||
|
||||
```powershell
|
||||
cd C:\Users\admin\Desktop\update-client
|
||||
|
||||
.\scripts\package-client.ps1 `
|
||||
-SourceDir .\out\bin `
|
||||
-ConfigFile .\config\app_config.json `
|
||||
-OutputDir .\dist\UpdateClient `
|
||||
-ZipFile .\dist\UpdateClient.zip
|
||||
```
|
||||
|
||||
`package-client.ps1` 会检查:
|
||||
|
||||
- 配置文件必填字段是否完整。
|
||||
- 主程序、Launcher、Updater、Bootstrap 是否存在。
|
||||
- 是否混入 Debug DLL、PDB、ILK。
|
||||
- 当前版本是否已有签名 Manifest 缓存。
|
||||
- 是否存在重复主程序。
|
||||
|
||||
生成结果:
|
||||
|
||||
```text
|
||||
dist/
|
||||
UpdateClient/
|
||||
UpdateClient.zip
|
||||
```
|
||||
|
||||
Linux 最终客户端包生成方式:
|
||||
|
||||
```bash
|
||||
cd /home/laluo/project/update-client
|
||||
|
||||
bash ./scripts/package-client.sh \
|
||||
--source-dir /path/to/SimCAE \
|
||||
--config-file /path/to/SimCAE/bin/config/app_config.json \
|
||||
--output-dir ./dist/UpdateClient-linux \
|
||||
--archive ./dist/UpdateClient-linux.tar.gz
|
||||
```
|
||||
|
||||
Linux 打包脚本会检查:
|
||||
|
||||
- `app_config.json` 必填字段是否完整。
|
||||
- 主程序、Launcher、Updater、Bootstrap 是否存在。
|
||||
- 是否混入 Debug 产物。
|
||||
- 当前版本是否已有签名 Manifest 缓存。
|
||||
- 是否存在重复主程序。
|
||||
|
||||
Linux 下如果程序安装在 `/opt`、`/usr/local` 等普通用户不可写目录,升级器无法像 Windows UAC 那样自动提权修改安装目录。正式部署前建议二选一:
|
||||
|
||||
1. 把软件安装到当前用户有写权限的目录,例如用户 home 下的应用目录。
|
||||
2. 由安装器创建专用目录和权限,让运行用户对软件目录有写入权限。
|
||||
|
||||
## 九、常见错误
|
||||
|
||||
1. 直接启动业务主程序提示 ticket 错误:应从 `Launcher.exe` 启动。
|
||||
2. 首次启动保存配置/状态文件失败:如果目录不可写,SDK 会弹出管理员权限确认框;用户取消或当前账号没有管理员权限时仍会失败。
|
||||
3. 首次启动设备登记失败:检查 `api_base_url`、`client_token`、`license_key`、服务端 License 状态。
|
||||
4. 提示 License 错误或过期:在后台确认 License 是否存在、是否被禁用或删除、是否超过最大设备数。
|
||||
5. 策略或 Manifest 验签失败:检查 `config/manifest_public_key.pem` 是否和服务端私钥匹配。
|
||||
6. 提示 signed manifest cache missing:先在后台发布一次 `current_version` 对应版本,并让客户端拿到该版本 Manifest。
|
||||
7. 升级后回滚:检查业务程序是否在 `health_check_timeout_ms` 内写入健康标记。
|
||||
8. 发布失败提示主程序不在根目录:服务端 `.env` 中 `RELEASE_MAIN_EXECUTABLE` 要和平台匹配。Windows 通常是 `bin/SimCAE.exe`;Linux 通常是 `bin/SimCAE`。
|
||||
9. 启动时提示 `无法定位程序输入点 ... Qt5*.dll`:通常是 Qt DLL 被不同版本覆盖或混用。恢复业务软件原始 Qt DLL,并重新打包 SDK;SimCAE 场景下不要使用 `-IncludeQtRuntime`。
|
||||
Reference in New Issue
Block a user