Compare commits
3 Commits
613607475e
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 750a68c49e | |||
| 7b7253943f | |||
| 0da7c2e296 |
@@ -1,23 +0,0 @@
|
|||||||
SimCAE Hub 客户端文档入口
|
|
||||||
========================
|
|
||||||
|
|
||||||
本目录记录 SimCAE Hub 的 Qt/C++ 客户端更新链路。当前方向是保留 Launcher / Updater / Bootstrap 的桌面客户端机制,适配 SimCAE Hub 当前 Go API,不用 Go 或 Web 技术重写客户端。
|
|
||||||
|
|
||||||
建议先按这个顺序阅读:
|
|
||||||
|
|
||||||
1. 01-客户端接入打包部署指南.md
|
|
||||||
说明客户端运行链路、配置字段、安装目录口径和接入限制。
|
|
||||||
|
|
||||||
2. 02-编译环境和第三方依赖说明.md
|
|
||||||
说明 Windows 和 Linux 下编译 Qt/C++ 客户端需要的工具、Qt、OpenSSL 和 CMake 命令。
|
|
||||||
|
|
||||||
3. ../打包成SDK.md
|
|
||||||
说明如何从 update-client 编译产物生成给 SIMCAE 开发者使用的 SDK 包。
|
|
||||||
|
|
||||||
4. ../config/server_config.json
|
|
||||||
编译进客户端资源的服务端地址配置,当前测试服务器是 http://192.168.1.158:18000。
|
|
||||||
|
|
||||||
5. ../scripts/ReadMe.txt
|
|
||||||
SDK 打包脚本和客户安装包打包脚本的简短说明。
|
|
||||||
|
|
||||||
客户端能力、接口链路、配置字段和接入限制统一看 01 文档。当前不包含邮箱、支付、告警、灰度发布等页面上没有的业务模块;崩溃报告作为旧系统兼容后端接口保留,具体看项目根目录的 项目细节.md。
|
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
# SimCAE Hub 客户端接入、打包和部署指南
|
|
||||||
|
|
||||||
本文说明 `update-client` 的当前实现。它保留 Launcher / Updater / Bootstrap 的桌面客户端机制,服务端协议使用 SimCAE Hub 当前 Go API。
|
|
||||||
|
|
||||||
## 1. 适用范围
|
|
||||||
|
|
||||||
当前客户端只覆盖项目已有页面和接口对应的能力:
|
|
||||||
|
|
||||||
1. 产品版本、软件发布、发布包和 Manifest。
|
|
||||||
2. 客户授权、在线命名用户席位和门户受控下载。
|
|
||||||
3. 在线检查更新、Manifest 拉取、受控下载、SHA-256 校验。
|
|
||||||
4. Manifest 签名验签、临时文件、断点重试、安装前后完整性校验。
|
|
||||||
|
|
||||||
邮箱、支付、灰度、告警等页面上没有的能力不属于当前范围。崩溃报告是 SimCAE Hub 保留的旧系统兼容后端接口,不属于 Launcher / Updater / Bootstrap 的更新链路;接入方需要崩溃上报时,按项目根目录 `项目细节.md` 里的崩溃报告接口说明调用。
|
|
||||||
|
|
||||||
## 2. 客户端程序组成
|
|
||||||
|
|
||||||
| 程序 | 作用 |
|
|
||||||
| --- | --- |
|
|
||||||
| `Launcher` | 客户日常启动入口,负责导入配置、使用 `client_token` 检查更新、启动 Updater 或主程序 |
|
|
||||||
| `Updater` | 负责拉取 Manifest、下载发布包、校验文件、准备安装事务 |
|
|
||||||
| `Bootstrap` | 负责在需要替换运行中文件时接管安装,并把结果交回 Updater |
|
|
||||||
| `MainApp` | 示例主程序,用来验证 launch ticket 和安装后完整性校验 |
|
|
||||||
| `Common` | 配置、HTTP、票据、完整性校验等公共代码 |
|
|
||||||
|
|
||||||
## 3. 当前在线更新链路
|
|
||||||
|
|
||||||
1. `Launcher` 启动后读取服务端生成的 `config/app_config.json`,并把静态配置导入当前用户的运行配置。
|
|
||||||
2. 如果配置里没有 `api_base_url`,客户端会回退到编译进 EXE 资源中的 `server_config.json`。
|
|
||||||
3. `Launcher` 确保存在 `device_id`,并检查 `client_token` 是否存在。
|
|
||||||
4. `Launcher` 调用 `GET /api/v1/client/update/authorized-check`,请求头带 `X-Client-Token`。
|
|
||||||
5. 如果服务端返回可用发布,`Launcher` 启动 `Updater`,并传入产品编码、渠道、目标版本和发布 ID。
|
|
||||||
6. `Updater` 调用 `GET /api/v1/client/update/manifest`,请求头继续带 `X-Client-Token`。
|
|
||||||
7. `Updater` 先校验服务端返回的 `manifestSha256`,再按配置决定是否强制要求 RSA-SHA256 签名。
|
|
||||||
8. `Updater` 从 Manifest 中读取每个文件的 `downloadUrl`、`sizeBytes` 和 `sha256`。
|
|
||||||
9. 下载请求统一带 `X-Client-Token`。
|
|
||||||
10. 下载使用 `.part` 临时文件保存进度,请求失败后按网络重试策略处理。
|
|
||||||
11. 文件下载完成后,客户端按 Manifest 校验文件大小和 SHA-256。
|
|
||||||
12. 安装前校验 staging 目录,安装完成后保存 Manifest 缓存,并可在主程序启动时再次校验已安装文件。
|
|
||||||
|
|
||||||
## 4. 关键配置字段
|
|
||||||
|
|
||||||
正式客户安装包里的 `config/app_config.json` 由服务端在上传发布包 ZIP 时自动生成。常用字段如下:
|
|
||||||
|
|
||||||
| 字段 | 说明 |
|
|
||||||
| --- | --- |
|
|
||||||
| `product_code` | SimCAE Hub 后台产品目录中的产品编码,例如 `stage2-dap` |
|
|
||||||
| `app_id` | 本地应用标识,默认和产品编码一致 |
|
|
||||||
| `channel` | 发布渠道,例如 `stable` |
|
|
||||||
| `current_version` | 当前本地安装版本,例如 `1.0.0` |
|
|
||||||
| `api_base_url` | 后端 API 地址,例如 `http://192.168.1.158:18000` |
|
|
||||||
| `client_token` | Launcher/Updater 调更新接口使用的部署级令牌,不绑定某一个客户 |
|
|
||||||
| `install_root` | 相对 Launcher/Updater 所在运行目录解析的更新根目录,决定 Updater、Bootstrap 和启动校验作用在哪棵目录 |
|
|
||||||
| `main_executable` | 相对运行目录解析的业务入口程序,通常是 `MainApp.exe` 或真实软件入口 |
|
|
||||||
| `launcher_executable` | 相对运行目录解析的 Launcher 文件名,主要用于提示和保持启动链路配置一致 |
|
|
||||||
| `updater_executable` | 相对运行目录解析的 Updater 文件名,Launcher 检查到更新后会启动它 |
|
|
||||||
| `bootstrap_executable` | 相对运行目录解析的 Bootstrap 文件名,Updater 需要替换文件时会启动它 |
|
|
||||||
| `platform` | 操作系统,例如 `windows` 或 `linux` |
|
|
||||||
| `arch` | 架构,例如 `x86_64` |
|
|
||||||
| `abi` | ABI,例如 `msvc`;没有时可留空 |
|
|
||||||
| `launch_token` | Launcher 和 MainApp 之间生成一次性启动票据的本地密钥 |
|
|
||||||
| `require_manifest_signature` | 是否强制要求 Manifest 必须带签名 |
|
|
||||||
| `verify_installed_on_start` | 主程序启动时是否按 Manifest 缓存校验已安装文件 |
|
|
||||||
|
|
||||||
`config/server_config.json` 会编译进客户端资源,作为 `api_base_url` 缺失时的兜底地址,当前测试服务器地址为:
|
|
||||||
|
|
||||||
`http://192.168.1.158:18000`
|
|
||||||
|
|
||||||
如果换服务器,可以改完该文件后重新编译客户端;正式客户包通常由服务端写入 `api_base_url`,不需要把 `server_config.json` 暴露给客户。
|
|
||||||
|
|
||||||
## 5. 编译和打包 SDK
|
|
||||||
|
|
||||||
客户端编译、带 Qt 和不带 Qt 两种 SDK 打包方式、输出目录、输出 ZIP 文件名,统一维护在 [../打包成SDK.md](../打包成SDK.md)。
|
|
||||||
|
|
||||||
本文件只说明 SDK 在客户软件里的接入位置和运行逻辑,不重复维护打包命令。
|
|
||||||
|
|
||||||
SDK 包不会包含最终 `app_config.json`、`server_config.json`、`server_config.qrc` 或 `manifest_public_key.pem`。这些最终配置在完整客户软件包或 Qt IFW 交付包上传到 SimCAE Hub 后由服务端生成。
|
|
||||||
|
|
||||||
## 6. 客户安装包配置
|
|
||||||
|
|
||||||
接入方应把以下文件放到客户软件目录的根目录或 `bin/` 目录:
|
|
||||||
|
|
||||||
1. `Launcher`
|
|
||||||
2. `Updater`
|
|
||||||
3. `Bootstrap`
|
|
||||||
4. `MainApp` 或真实业务主程序
|
|
||||||
5. `config/` 目录,可以先为空
|
|
||||||
|
|
||||||
### 6.1 标准目录结构和路径口径
|
|
||||||
|
|
||||||
更新系统不要求必须放在客户软件根目录。它可以放在 `SimCAE/` 根目录,也可以放在 `SimCAE/bin/` 目录。关键是让客户端配置里的 `install_root` 和服务端 Manifest 文件路径使用同一套口径。
|
|
||||||
|
|
||||||
先区分三个目录概念:
|
|
||||||
|
|
||||||
| 概念 | 说明 |
|
|
||||||
| --- | --- |
|
|
||||||
| 运行目录 | Launcher、Updater、Bootstrap 所在目录,由客户端自动识别 |
|
|
||||||
| `install_root` | 相对运行目录解析的更新根目录,Updater 下载、校验、备份、回滚和 Bootstrap 替换文件都以它为范围 |
|
|
||||||
| Manifest `files[].path` | 服务端生成的安装相对路径,客户端会把它拼到 `install_root` 下面 |
|
|
||||||
|
|
||||||
目录结构一:更新系统放在软件根目录。
|
|
||||||
|
|
||||||
```text
|
|
||||||
SimCAE/
|
|
||||||
Launcher.exe
|
|
||||||
Updater.exe
|
|
||||||
Bootstrap.exe
|
|
||||||
MainApp.exe
|
|
||||||
config/
|
|
||||||
app_config.json
|
|
||||||
App/
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
对应配置:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"install_root": ".",
|
|
||||||
"main_executable": "MainApp.exe",
|
|
||||||
"launcher_executable": "Launcher.exe",
|
|
||||||
"updater_executable": "Updater.exe",
|
|
||||||
"bootstrap_executable": "Bootstrap.exe"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
目录结构二:更新系统和启动入口放在 `bin/`。
|
|
||||||
|
|
||||||
```text
|
|
||||||
SimCAE/
|
|
||||||
bin/
|
|
||||||
Launcher.exe
|
|
||||||
Updater.exe
|
|
||||||
Bootstrap.exe
|
|
||||||
MainApp.exe
|
|
||||||
config/
|
|
||||||
app_config.json
|
|
||||||
App/
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
如果希望整个 `SimCAE/` 都属于更新范围,对应配置:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"install_root": "..",
|
|
||||||
"main_executable": "MainApp.exe",
|
|
||||||
"launcher_executable": "Launcher.exe",
|
|
||||||
"updater_executable": "Updater.exe",
|
|
||||||
"bootstrap_executable": "Bootstrap.exe"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
这表示 Launcher 从 `bin/` 启动 `MainApp.exe`,Updater 和 Bootstrap 更新的是 `bin/` 的上一级,也就是整个 `SimCAE/`。
|
|
||||||
|
|
||||||
服务端发布包路径要和客户端 `install_root` 对应:
|
|
||||||
|
|
||||||
| 客户端配置 | 服务端 Manifest 路径口径 |
|
|
||||||
| --- | --- |
|
|
||||||
| 更新系统在根目录,`install_root` 是 `.` | `MainApp.exe`、`App/xxx.dll` 相对 `SimCAE/` |
|
|
||||||
| 更新系统在 `bin/`,`install_root` 是 `..` | `bin/MainApp.exe`、`App/xxx.dll` 相对 `SimCAE/` |
|
|
||||||
|
|
||||||
当前管理后台“发布包”上传接口会使用上传文件名作为 `artifactName`,后端按安全文件名校验。当前稳定支持的是发布一个完整安装包或压缩包文件,或者把文件放在 `install_root` 根层级;还不是“自动解析压缩包并生成 App/bin 多文件 Manifest”的完整安装器。后续如果要让在线 Updater 直接把多个文件铺到 `App/`、`bin/` 等子目录,需要在现有发布包页面和 Go 后端上继续增强安全相对路径或 Manifest 文件清单生成能力。
|
|
||||||
|
|
||||||
如果后续要支持“更新系统在 `bin/`,但只校验和更新 `App/`”这类更窄的安装根目录,需要在管理后台和 Go 后端增加对应配置项,让服务端生成 `../App` 这类定制 `install_root`。当前服务端自动生成配置时只使用标准的 `.` 或 `..`。
|
|
||||||
|
|
||||||
如果开启 `verify_installed_on_start`,客户端会扫描 `install_root` 下的 EXE 和 DLL。整包 Manifest 中 `required=true` 的核心文件必须存在且 SHA-256 匹配;`required=false` 的可选组件文件可以由 MaintenanceTool 管理,缺失时不会阻止启动。可选组件建议放在独立目录中,例如 `plugins/dap/`,不要和核心程序 DLL 混放。
|
|
||||||
|
|
||||||
上传完整客户软件 ZIP 时,服务端会根据发布包记录自动写入这些关键值:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"product_code": "stage2-dap",
|
|
||||||
"channel": "stable",
|
|
||||||
"current_version": "1.1.0",
|
|
||||||
"api_base_url": "http://192.168.1.158:18000",
|
|
||||||
"client_token": "<由服务器 .env 配置>",
|
|
||||||
"install_root": ". 或 ..",
|
|
||||||
"platform": "windows",
|
|
||||||
"arch": "x86_64",
|
|
||||||
"abi": "msvc"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`install_root` 由服务端根据 Launcher 所在位置自动判断:更新系统在软件根目录时写 `.`,在 `bin/` 目录时写 `..`。
|
|
||||||
|
|
||||||
## 7. 运行数据位置
|
|
||||||
|
|
||||||
Windows 运行数据目录:
|
|
||||||
|
|
||||||
`%LOCALAPPDATA%\SimCAE\HubUpdateClient\installations\<安装目录SHA256>\`
|
|
||||||
|
|
||||||
Linux 运行数据目录:
|
|
||||||
|
|
||||||
`$XDG_DATA_HOME/SimCAE/HubUpdateClient/installations/<安装目录SHA256>/`
|
|
||||||
|
|
||||||
未设置 `XDG_DATA_HOME` 时通常是:
|
|
||||||
|
|
||||||
`~/.local/share/SimCAE/HubUpdateClient/installations/<安装目录SHA256>/`
|
|
||||||
|
|
||||||
Manifest 缓存保存在运行数据目录下的 `update/manifest_cache`。
|
|
||||||
|
|
||||||
## 8. 常见问题
|
|
||||||
|
|
||||||
1. 客户门户登录失败:检查客户门户账号是否已激活、客户是否生效、密码是否正确。
|
|
||||||
2. 检查更新没有结果:检查后台发布是否已发布、发布包是否可用、产品编码、渠道和平台参数是否一致。
|
|
||||||
3. 下载 401:检查发布包中的 `config/app_config.json` 是否由服务端生成,`client_token` 是否和服务器 `.env` 中的 `SIMCAE_CLIENT_TOKEN` 一致。
|
|
||||||
4. Manifest 校验失败:检查服务端 Manifest 是否被篡改、发布包 SHA-256 是否和实际文件一致。
|
|
||||||
5. 强制签名失败:确认 `manifest_public_key.pem` 与服务端私钥匹配;如果服务端暂未启用签名,测试环境可先把 `require_manifest_signature` 设为 `false`。
|
|
||||||
6. 启动主程序失败:检查 `main_executable` 和 `install_root` 是否指向真实文件。
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
# SimCAE Hub 客户端编译环境和第三方依赖说明
|
|
||||||
|
|
||||||
本文说明 `update-client` 的 Qt/C++ 客户端编译环境。客户端保留 Launcher / Updater / Bootstrap 机制,依赖 Qt、CMake 和 OpenSSL。
|
|
||||||
|
|
||||||
## 1. 通用要求
|
|
||||||
|
|
||||||
| 依赖 | 要求 |
|
|
||||||
| --- | --- |
|
|
||||||
| CMake | 建议 3.20 或更高版本 |
|
|
||||||
| C++ | C++17 |
|
|
||||||
| Qt | Qt 5,至少需要 Core、Network、Gui、Widgets |
|
|
||||||
| OpenSSL | 用于 Manifest RSA-SHA256 验签 |
|
|
||||||
| 编译器 | Windows 推荐 Visual Studio 2022 x64,Linux 推荐 gcc/g++ |
|
|
||||||
|
|
||||||
项目已提供 CMake Preset:
|
|
||||||
|
|
||||||
| Preset | 平台 | 用途 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `x64-debug` | Windows | Debug 编译 |
|
|
||||||
| `x64-release` | Windows | Release 编译 |
|
|
||||||
| `linux-x64-debug` | Linux | Debug 编译 |
|
|
||||||
| `linux-x64-release` | Linux | Release 编译 |
|
|
||||||
|
|
||||||
## 2. Windows 环境
|
|
||||||
|
|
||||||
建议安装:
|
|
||||||
|
|
||||||
1. Visual Studio 2022,勾选 Desktop development with C++。
|
|
||||||
2. Qt 5 x64,版本可以与当前团队环境保持一致。
|
|
||||||
3. CMake。
|
|
||||||
4. OpenSSL x64。
|
|
||||||
|
|
||||||
如果 Qt 没有加入环境变量,可以在编译前指定 `CMAKE_PREFIX_PATH` 或 `Qt5_DIR`。示例:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$env:CMAKE_PREFIX_PATH = "C:\Qt\5.15.2\msvc2019_64"
|
|
||||||
```
|
|
||||||
|
|
||||||
如果 Qt 安装在别的位置,只改这一行。
|
|
||||||
|
|
||||||
OpenSSL 可以放在 `update-client/thirdparty/OpenSSL-Win64`,也可以在配置时通过 `SIMCAE_OPENSSL_ROOT` 指向自定义目录。
|
|
||||||
|
|
||||||
## 3. Linux 环境
|
|
||||||
|
|
||||||
Ubuntu 示例:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y build-essential cmake qtbase5-dev qttools5-dev qttools5-dev-tools libssl-dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Linux 下通常直接使用系统 OpenSSL;如需指定自定义 OpenSSL,可用 CMake 变量配置。
|
|
||||||
|
|
||||||
## 4. 编译输出
|
|
||||||
|
|
||||||
Windows Release 可执行文件输出目录:
|
|
||||||
|
|
||||||
`update-client/out/bin/Release`
|
|
||||||
|
|
||||||
Windows CMake 构建目录:
|
|
||||||
|
|
||||||
`update-client/out/build/x64-release`
|
|
||||||
|
|
||||||
Linux Release 可执行文件输出目录以当前 CMake Preset 和构建脚本为准,SDK 打包时通过 `--source-dir` 指定。
|
|
||||||
|
|
||||||
实际打包 SDK 前,应确认 Release 输出目录中至少包含:
|
|
||||||
|
|
||||||
1. `Launcher`
|
|
||||||
2. `Updater`
|
|
||||||
3. `Bootstrap`
|
|
||||||
4. 可选的示例 `MainApp`
|
|
||||||
|
|
||||||
最终客户软件包里的 `config/app_config.json` 和 `config/manifest_public_key.pem` 由服务端在发布包上传时生成;`server_config.json` 会编译进 EXE 作为兜底地址,不需要进入 SDK 包。
|
|
||||||
|
|
||||||
SDK 打包见 `../打包成SDK.md`,客户端运行链路和接入限制见 `01-客户端接入打包部署指南.md`。
|
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
# SimCAE Hub 更新客户端
|
||||||
|
|
||||||
|
`update-client` 是 SimCAE Hub 的 Qt/C++ 整包更新客户端,包含 `Launcher`、`Updater`、`Bootstrap` 和一个示例 `MainApp`。它负责检查整包更新、拉取 Manifest、下载发布包、校验哈希并完成本地安装。
|
||||||
|
|
||||||
|
组件级安装、组件级更新和卸载由 Qt IFW 生成的 `maintenancetool.exe` 负责。`update-client` 不替代 MaintenanceTool,也不读取 Qt IFW 的 `Updates.xml`。
|
||||||
|
|
||||||
|
## 一、当前接入方式
|
||||||
|
|
||||||
|
当前 SIMCAE 的标准接入方式是:
|
||||||
|
|
||||||
|
| 阶段 | 发生什么 |
|
||||||
|
| --- | --- |
|
||||||
|
| SDK 打包 | `update-client` 只打出 `Launcher.exe`、`Updater.exe`、`Bootstrap.exe` 和运行库 |
|
||||||
|
| SIMCAE 打包 | SIMCAE 的 `installer` 规则把 SDK 文件放进核心组件 `com.simcae.app` |
|
||||||
|
| 本地 IFW package | Hub 更新客户端位于 `package/packages/com.simcae.app/data/view/bin` |
|
||||||
|
| 上传到 Hub | 服务端校验 IFW 交付包,并自动注入最终客户配置 |
|
||||||
|
| 客户安装 | 客户从门户下载安装器,安装后得到 `maintenancetool.exe` 和 `view/bin/Launcher.exe` |
|
||||||
|
| 日常启动 | 客户通过 `Launcher.exe` 或安装器创建的快捷方式启动 SimCAE |
|
||||||
|
|
||||||
|
最终客户不需要手动填写 `app_config.json`、服务器地址、token、产品编码、平台架构或版本号。
|
||||||
|
|
||||||
|
## 二、程序组成
|
||||||
|
|
||||||
|
| 程序 | 作用 |
|
||||||
|
| --- | --- |
|
||||||
|
| `Launcher` | 客户日常启动入口,读取配置、检查整包更新、启动 `Updater` 或主程序 |
|
||||||
|
| `Updater` | 拉取 Manifest、下载发布包、校验文件、准备安装事务 |
|
||||||
|
| `Bootstrap` | 替换运行中文件,并把安装结果交回 `Updater` |
|
||||||
|
| `MainApp` | 示例主程序,用于验证 launch ticket 和启动前完整性校验 |
|
||||||
|
| `Common` | 配置、HTTP、票据、路径、Manifest 和完整性校验等公共代码 |
|
||||||
|
|
||||||
|
真实接入 SIMCAE 时,`MainApp` 只是示例程序。正式主程序是 SIMCAE 自己的 `SimCAE.exe`。
|
||||||
|
|
||||||
|
## 三、在线更新链路
|
||||||
|
|
||||||
|
1. 客户启动 `Launcher.exe`。
|
||||||
|
2. 客户端读取服务端注入的初始配置。
|
||||||
|
3. 首次启动时,客户端会把 `app_config.json` 中的运行配置导入本机用户配置。
|
||||||
|
4. 为减少明文配置暴露,导入成功后客户端可能清空安装目录里的 `app_config.json`。
|
||||||
|
5. `Launcher` 确保本机有 `device_id`。
|
||||||
|
6. `Launcher` 使用 `X-Client-Token` 调用更新检查接口。
|
||||||
|
7. 如果服务端返回可用发布,`Launcher` 启动 `Updater`。
|
||||||
|
8. `Updater` 使用 `X-Client-Token` 拉取 Manifest。
|
||||||
|
9. `Updater` 校验 Manifest 摘要,并按配置决定是否要求签名。
|
||||||
|
10. `Updater` 按 Manifest 下载文件。
|
||||||
|
11. 每个文件下载完成后校验大小和 SHA-256。
|
||||||
|
12. 安装前校验 staging 目录。
|
||||||
|
13. 如需替换运行中文件,`Bootstrap` 接管安装。
|
||||||
|
14. 安装完成后保存 Manifest 缓存和本地状态。
|
||||||
|
15. 如果主程序开启启动前完整性校验,下次启动时会按本地 Manifest 缓存校验已安装文件。
|
||||||
|
|
||||||
|
更新接口使用部署级 `client_token`,不使用客户邮箱密码。客户账号和授权主要控制门户下载、客户权益和席位,不要求最终客户启动软件时再登录。
|
||||||
|
|
||||||
|
## 四、当前 SIMCAE 目录规则
|
||||||
|
|
||||||
|
客户安装完成后的关键目录是:
|
||||||
|
|
||||||
|
| 路径 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `maintenancetool.exe` | Qt IFW 生成的组件维护工具,位于安装根目录 |
|
||||||
|
| `components.xml` | Qt IFW 记录的已安装组件状态,位于安装根目录 |
|
||||||
|
| `network.xml` | Qt IFW 记录的组件仓库地址,位于安装根目录 |
|
||||||
|
| `view/bin/Launcher.exe` | Hub 更新客户端启动入口 |
|
||||||
|
| `view/bin/Updater.exe` | Hub 整包更新程序 |
|
||||||
|
| `view/bin/Bootstrap.exe` | Hub 安装接管程序 |
|
||||||
|
| `view/bin/SimCAE.exe` | SIMCAE 业务主程序 |
|
||||||
|
| `view/bin/config/app_config.json` | 服务端注入的初始客户配置 |
|
||||||
|
|
||||||
|
当前服务端会识别三种运行目录:
|
||||||
|
|
||||||
|
| 运行目录 | 服务端写入的 `install_root` | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 软件根目录 | `.` | `Launcher` 和主程序就在软件根目录 |
|
||||||
|
| `bin` | `..` | `Launcher` 在一层 `bin` 目录中 |
|
||||||
|
| `view/bin` | `../..` | 当前 SIMCAE 标准结构,`Launcher` 在 `view/bin` 中 |
|
||||||
|
|
||||||
|
`install_root` 不是让客户手动填写的字段。上传发布包或 Qt IFW 交付包时,服务端会根据 `Launcher`、`Updater`、`Bootstrap` 的实际位置自动判断。
|
||||||
|
|
||||||
|
## 五、服务端注入的配置
|
||||||
|
|
||||||
|
正式客户包中的 `app_config.json` 由服务端生成或替换。开发者打 SDK 时不放最终配置,客户也不手动改配置。
|
||||||
|
|
||||||
|
服务端生成配置时,信息来源如下:
|
||||||
|
|
||||||
|
| 配置内容 | 来源 |
|
||||||
|
| --- | --- |
|
||||||
|
| `product_code`、`app_id` | 管理后台“产品目录”的产品编码 |
|
||||||
|
| `app_name` | 管理后台“产品目录”的产品名称 |
|
||||||
|
| `channel` | 管理后台“软件发布”的发布通道 |
|
||||||
|
| `current_version` | 管理后台“产品版本”的版本号 |
|
||||||
|
| `platform`、`arch`、`abi` | 管理后台“平台管理”和发布包选择的平台 |
|
||||||
|
| `api_base_url` | 服务端 `.env` 的 `SIMCAE_CLIENT_API_BASE_URL` |
|
||||||
|
| `client_token` | 服务端 `.env` 的 `SIMCAE_CLIENT_TOKEN` |
|
||||||
|
| `launch_token` | 服务端 `.env` 的 `SIMCAE_LAUNCH_TOKEN` |
|
||||||
|
| `install_root` | 服务端根据运行目录自动判断 |
|
||||||
|
| `main_executable` | 服务端在运行目录中识别到的业务主程序,SIMCAE 当前为 `SimCAE.exe` |
|
||||||
|
| `launcher_executable` | 按平台生成,Windows 为 `Launcher.exe` |
|
||||||
|
| `updater_executable` | 按平台生成,Windows 为 `Updater.exe` |
|
||||||
|
| `bootstrap_executable` | 按平台生成,Windows 为 `Bootstrap.exe` |
|
||||||
|
| `require_manifest_signature` | 服务端 Manifest 签名配置 |
|
||||||
|
| `verify_installed_on_start` | 当前服务端默认写入 `false`,需要强制启动校验时再按发布策略开启 |
|
||||||
|
|
||||||
|
如果上传包里已经带了旧的 `app_config.json`、`server_config.json`、`server_config.qrc` 或 `manifest_public_key.pem`,服务端会按当前发布信息重新处理,不让开发机临时配置直接进入最终客户包。
|
||||||
|
|
||||||
|
## 六、本地调试配置
|
||||||
|
|
||||||
|
正式发布不要手写最终 `app_config.json`。如果开发者只是在本机调试 `Launcher` 或 `Updater`,可以创建未提交的 `config/app_config.local.json`。
|
||||||
|
|
||||||
|
CMake 只在本地输出目录还没有 `config/app_config.json` 时,才会把 `app_config.local.json` 复制成调试用配置。这个文件只服务本机调试,不代表服务端最终注入结果。
|
||||||
|
|
||||||
|
`config/server_config.json` 和 `config/server_config.qrc` 用于把兜底 API 地址编译进 EXE。正式客户包优先使用服务端注入的 `api_base_url`,一般不需要让客户看到或修改 `server_config.json`。
|
||||||
|
|
||||||
|
## 七、启动门禁
|
||||||
|
|
||||||
|
如果 SIMCAE 主程序开启 `SimCAE_UseLauncher=ON`,用户直接双击 `SimCAE.exe` 会被拦截,必须通过 `Launcher.exe` 启动。
|
||||||
|
|
||||||
|
这套机制依赖 `launch_token`:
|
||||||
|
|
||||||
|
| 位置 | 要求 |
|
||||||
|
| --- | --- |
|
||||||
|
| 服务端 `.env` | 必须配置 `SIMCAE_LAUNCH_TOKEN` |
|
||||||
|
| SIMCAE 编译期 | 主程序编译时使用同一个 token |
|
||||||
|
| 客户端配置 | 服务端把同一个 token 写入最终客户配置 |
|
||||||
|
|
||||||
|
如果三处 token 不一致,就会出现“直接双击被拦住,但从 `Launcher` 启动也失败”的问题。
|
||||||
|
|
||||||
|
## 八、Manifest 和哈希校验
|
||||||
|
|
||||||
|
整包更新使用 SimCAE Hub Manifest,不使用 Qt IFW 的 `Updates.xml`。
|
||||||
|
|
||||||
|
Manifest 负责描述:
|
||||||
|
|
||||||
|
| 内容 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 发布版本 | 本次更新属于哪个产品、版本线、版本和通道 |
|
||||||
|
| 文件清单 | 本次发布包含哪些文件 |
|
||||||
|
| 下载地址 | 每个文件从哪个受控接口下载 |
|
||||||
|
| 文件大小 | 客户端下载后必须一致 |
|
||||||
|
| SHA-256 | 客户端下载后必须一致 |
|
||||||
|
| 是否必选 | 必选文件缺失会阻止启动,可选组件文件可由 MaintenanceTool 管理 |
|
||||||
|
|
||||||
|
服务端返回 Manifest 前会重新检查发布包文件是否存在、大小是否一致、SHA-256 是否一致。客户端下载完成后也会再次校验大小和 SHA-256。
|
||||||
|
|
||||||
|
## 九、和 MaintenanceTool 的边界
|
||||||
|
|
||||||
|
| 能力 | 使用程序 | 文件格式 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 整包更新 | `Launcher`、`Updater`、`Bootstrap` | SimCAE Hub 发布包和 Manifest |
|
||||||
|
| 组件安装、更新、移除 | `maintenancetool.exe` | Qt IFW repository 和 `Updates.xml` |
|
||||||
|
|
||||||
|
两条线可以共存,但不要混淆:
|
||||||
|
|
||||||
|
1. `Updater` 不读取 `Updates.xml`。
|
||||||
|
2. `MaintenanceTool` 不读取 SimCAE Hub Manifest。
|
||||||
|
3. `Updater` 不拉起 `MaintenanceTool`。
|
||||||
|
4. `MaintenanceTool` 由客户手动打开,或由 Qt IFW 自己的流程使用。
|
||||||
|
5. 核心组件通常包含 `Launcher`、`Updater`、`Bootstrap` 和 `SimCAE.exe`。
|
||||||
|
6. 可选组件例如 DAP 插件,可以由 MaintenanceTool 单独安装、更新或移除。
|
||||||
|
|
||||||
|
## 十、编译环境
|
||||||
|
|
||||||
|
| 依赖 | 要求 |
|
||||||
|
| --- | --- |
|
||||||
|
| CMake | 建议 3.20 或更高版本 |
|
||||||
|
| C++ | C++17 |
|
||||||
|
| Qt | Qt 5,至少需要 Core、Network、Gui、Widgets |
|
||||||
|
| OpenSSL | 用于 Manifest RSA-SHA256 验签 |
|
||||||
|
| 编译器 | Windows 推荐 Visual Studio 2022 x64,Linux 推荐 gcc/g++ |
|
||||||
|
|
||||||
|
项目提供的 CMake Preset:
|
||||||
|
|
||||||
|
| Preset | 平台 | 用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `x64-debug` | Windows | Debug 编译 |
|
||||||
|
| `x64-release` | Windows | Release 编译 |
|
||||||
|
| `linux-x64-debug` | Linux | Debug 编译 |
|
||||||
|
| `linux-x64-release` | Linux | Release 编译 |
|
||||||
|
|
||||||
|
## 十一、Windows 编译
|
||||||
|
|
||||||
|
建议安装 Visual Studio 2022、Qt 5 x64、CMake 和 OpenSSL x64。
|
||||||
|
|
||||||
|
如果 Qt 没有加入环境变量,可以在编译前指定:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:CMAKE_PREFIX_PATH = "C:\Qt\5.15.2\msvc2019_64"
|
||||||
|
```
|
||||||
|
|
||||||
|
当前测试机 OpenSSL 路径是 `C:\Program Files\OpenSSL-Win64`,Release 编译命令:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cmake --preset x64-release -DSIMCAE_OPENSSL_ROOT="C:\Program Files\OpenSSL-Win64"
|
||||||
|
cmake --build --preset x64-release
|
||||||
|
```
|
||||||
|
|
||||||
|
如果 OpenSSL 安装在其他目录,只改 `SIMCAE_OPENSSL_ROOT` 这一项。
|
||||||
|
|
||||||
|
Windows Release 产物通常输出到 `out/bin/Release`。
|
||||||
|
|
||||||
|
检查核心程序:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-Path .\out\bin\Release\Launcher.exe
|
||||||
|
Test-Path .\out\bin\Release\Updater.exe
|
||||||
|
Test-Path .\out\bin\Release\Bootstrap.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
预期都返回 `True`。
|
||||||
|
|
||||||
|
## 十二、Linux 编译
|
||||||
|
|
||||||
|
Ubuntu 示例:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y build-essential cmake qtbase5-dev qttools5-dev qttools5-dev-tools libssl-dev
|
||||||
|
cmake --preset linux-x64-release
|
||||||
|
cmake --build --preset linux-x64-release
|
||||||
|
```
|
||||||
|
|
||||||
|
Linux 下通常直接使用系统 OpenSSL;如果需要指定自定义 OpenSSL,也可以通过 CMake 变量配置。
|
||||||
|
|
||||||
|
## 十三、打包 SDK
|
||||||
|
|
||||||
|
SDK 打包流程见当前目录 [updater打包成SDK.md](updater打包成SDK.md)。SIMCAE 拿到 SDK 后的安装器、交付包和上传流程见 [SIMCAE打包上传.md](SIMCAE打包上传.md)。
|
||||||
|
|
||||||
|
常用输出:
|
||||||
|
|
||||||
|
| 输出 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `dist\UpdateClientSDK` | 不带 Qt 运行库的 SDK 展开目录 |
|
||||||
|
| `dist\UpdateClientSDK.zip` | 不带 Qt 运行库的 SDK 压缩包 |
|
||||||
|
| `dist\UpdateClientSDK-With-QtDll` | 带 Qt 运行库 DLL 的 SDK 展开目录 |
|
||||||
|
| `dist\UpdateClientSDK-With-QtDll.zip` | 推荐交给 SIMCAE 开发者的 SDK 压缩包 |
|
||||||
|
|
||||||
|
SDK 不包含最终客户配置。`With-QtDll` 表示包里带的是运行所需的 Qt DLL,不是完整 Qt SDK。SDK 的目标是给 SIMCAE 打包流程提供更新客户端程序和运行库。
|
||||||
|
|
||||||
|
## 十四、运行数据位置
|
||||||
|
|
||||||
|
Windows 运行配置会导入当前用户配置,按安装运行目录计算 installation id。运行数据目录通常位于:
|
||||||
|
|
||||||
|
`%LOCALAPPDATA%\SimCAE\HubUpdateClient\installations\<安装目录SHA256>\`
|
||||||
|
|
||||||
|
Linux 运行数据目录通常位于:
|
||||||
|
|
||||||
|
`$XDG_DATA_HOME/SimCAE/HubUpdateClient/installations/<安装目录SHA256>/`
|
||||||
|
|
||||||
|
未设置 `XDG_DATA_HOME` 时通常是:
|
||||||
|
|
||||||
|
`~/.local/share/SimCAE/HubUpdateClient/installations/<安装目录SHA256>/`
|
||||||
|
|
||||||
|
Manifest 缓存保存在运行数据目录下的 `update/manifest_cache`。
|
||||||
|
|
||||||
|
## 十五、常见问题
|
||||||
|
|
||||||
|
| 现象 | 排查方向 |
|
||||||
|
| --- | --- |
|
||||||
|
| 客户启动后提示配置不完整 | 检查交付包是否经过 SimCAE Hub 上传注入,不要直接拿本地未注入包给客户 |
|
||||||
|
| 检查更新没有结果 | 检查后台发布是否已发布、发布包是否可用、产品编码、通道和平台是否一致 |
|
||||||
|
| 下载返回 401 | 检查客户包里的 `client_token` 是否来自当前服务端 `.env` |
|
||||||
|
| Manifest 校验失败 | 检查服务端文件是否被手工改过,大小和 SHA-256 是否与数据库一致 |
|
||||||
|
| 强制签名失败 | 检查 `manifest_public_key.pem` 与服务端私钥是否匹配 |
|
||||||
|
| 主程序启动失败 | 检查 `main_executable` 和运行目录是否正确 |
|
||||||
|
| 从 `Launcher` 启动也被拦截 | 检查服务端、SIMCAE 编译期和客户配置中的 `launch_token` 是否一致 |
|
||||||
|
| MaintenanceTool 看不到组件更新 | 检查 IFW repository 地址、`Updates.xml` 和组件版本是否正确 |
|
||||||
+621
@@ -0,0 +1,621 @@
|
|||||||
|
# SIMCAE 打包上传
|
||||||
|
|
||||||
|
本文站在 SIMCAE 开发者和发布人员的角度,说明拿到 Hub 更新客户端 SDK 后,SIMCAE 怎么打安装器、怎么生成 Qt IFW 交付包、怎么上传到 SimCAE Hub。
|
||||||
|
|
||||||
|
服务端部署流程见 simcae-hub 项目根目录《服务端部署.md》。普通发布人员只需要拿到已经打好的更新客户端 SDK;如果需要重新生成 SDK,见源代码仓库 `SIMCAE/update-client/updater打包成SDK.md`。
|
||||||
|
|
||||||
|
本文下面的命令默认在 SIMCAE 项目根目录执行。下面用 SIMCAE 当前放在 simcae-hub 项目里的情况举例:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd .\SIMCAE
|
||||||
|
```
|
||||||
|
|
||||||
|
进入后再使用相对路径,例如 `.\installer`、`.\update-client`、`.\out\build\...`。这样不要求开发者的 SIMCAE 一定放在某个固定磁盘目录。
|
||||||
|
|
||||||
|
## 一、先理解交付物
|
||||||
|
|
||||||
|
客户端交付会涉及三类文件:
|
||||||
|
|
||||||
|
| 交付物 | 给谁用 | 作用 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Hub 更新客户端 SDK | SIMCAE 开发者 | 提供 `Launcher.exe`、`Updater.exe`、`Bootstrap.exe` 和必要运行库 |
|
||||||
|
| Qt IFW 交付包 ZIP | 上传到 SimCAE Hub | 包含 IFW package 和 repository,服务端会校验、注入配置、发布仓库并重新生成客户安装器 |
|
||||||
|
| 客户安装器 | 最终客户 | 客户从门户下载后双击安装,安装后得到 `maintenancetool.exe` |
|
||||||
|
|
||||||
|
正式主线是:开发者只上传一个 Qt IFW 交付包 ZIP,客户只从门户下载客户安装器。客户不需要手动改服务器地址、token 或 `app_config.json`。
|
||||||
|
|
||||||
|
## 二、准备 Hub 更新客户端 SDK
|
||||||
|
|
||||||
|
开发者应拿到 `UpdateClientSDK-With-QtDll.zip`。
|
||||||
|
|
||||||
|
这个 ZIP 由 `update-client` 仓库的 SDK 打包脚本生成,SDK 维护者按源代码仓库 `SIMCAE/update-client/updater打包成SDK.md` 操作即可。
|
||||||
|
|
||||||
|
建议手动解压到 SIMCAE 仓库内的固定相对目录:`.\update-client\dist\UpdateClientSDK-With-QtDll`。
|
||||||
|
|
||||||
|
这里的 `With-QtDll` 表示包里带的是运行所需的 Qt DLL,不是完整 Qt SDK。
|
||||||
|
|
||||||
|
如果公司内部统一把 SDK 放在别的位置,也可以,只要后面 `$UpdateClientSdk` 指向解压后的 SDK 目录即可。
|
||||||
|
|
||||||
|
解压后至少应有:
|
||||||
|
|
||||||
|
- `bin\Launcher.exe`
|
||||||
|
- `bin\Updater.exe`
|
||||||
|
- `bin\Bootstrap.exe`
|
||||||
|
|
||||||
|
SDK 包不应该包含最终客户配置,例如 `app_config.json`、`server_config.json`、`server_config.qrc`、`manifest_public_key.pem`。这些最终配置由服务端在上传发布包时生成或注入。
|
||||||
|
|
||||||
|
## 三、准备 SIMCAE 已编译产物
|
||||||
|
|
||||||
|
默认 SIMCAE 已经在开发机上完成 Release 编译。客户端打包文档不要求每次重新全量编译 SIMCAE,因为 SIMCAE 工程很大,打安装包时通常只需要复用已有 Release 产物。
|
||||||
|
|
||||||
|
需要确认:
|
||||||
|
|
||||||
|
| 内容 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| SIMCAE Release 构建目录 | 已经存在 `SimCAE.exe`、库文件、资源文件 |
|
||||||
|
| Qt Installer Framework | 已经安装 `binarycreator.exe` 和 `repogen.exe` |
|
||||||
|
| DAP 运行时 | 如果启用 DAP 组件,`DAPrailCalxml` 等运行时已放在打包规则要求的位置 |
|
||||||
|
| Hub 更新客户端 SDK | 已解压,并能找到 `Launcher.exe`、`Updater.exe`、`Bootstrap.exe` |
|
||||||
|
|
||||||
|
如果业务主程序启用了“必须从 Launcher 启动”的门禁,SIMCAE 编译时使用的 launch token 必须和服务端 `.env` 里的 `SIMCAE_LAUNCH_TOKEN` 一致。
|
||||||
|
|
||||||
|
## 四、设置本次打包版本
|
||||||
|
|
||||||
|
SIMCAE 安装器文件名、IFW 组件 `package.xml` 版本、repository 里的 `Updates.xml` 版本都来自 CMake 变量 `SimCAE_Version`。这个版本默认读取 SIMCAE 仓库最近的纯数字 Git tag,例如 `1.1.3`。
|
||||||
|
|
||||||
|
先把几个容易混淆的“版本标签”分清楚:
|
||||||
|
|
||||||
|
| 名称 | 写在哪里 | 谁会读取 | 作用 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Git tag | SIMCAE 仓库提交,例如 `git tag 1.1.3` | CMake 版本脚本 | 生成 `SimCAE_Version`,再写入安装器文件名和组件元数据 |
|
||||||
|
| 组件版本 | `packages/<组件ID>/meta/package.xml` 的 `<Version>` | `repogen.exe` | 生成 repository 时写入 `Updates.xml` |
|
||||||
|
| repository 组件版本 | `Updates.xml` 里的 `<PackageUpdate><Name>...` 和 `<Version>...` | `maintenancetool.exe` | 客户端判断某个组件是否需要更新 |
|
||||||
|
| ZIP 文件名 | 例如 `SimCAE-Delivery-1.1.3-windows_x86_64-msvc.zip` | 人和管理后台记录 | 方便识别上传文件,不是 MaintenanceTool 的更新依据 |
|
||||||
|
|
||||||
|
所以 `git tag 1.1.3` 打的是 SIMCAE 源码提交标签,不是给 ZIP 文件打标签。它会被 CMake 读取后间接变成组件 `package.xml` 里的版本。真正决定 MaintenanceTool 是否更新的是服务器 repository 的 `Updates.xml`,而 `Updates.xml` 又来自组件自己的 `package.xml`。
|
||||||
|
|
||||||
|
正式发布时推荐在 SIMCAE 仓库给本次发布提交打纯数字 tag,再打包:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git tag 1.1.3
|
||||||
|
```
|
||||||
|
|
||||||
|
如果只是本机演示,不想改 SIMCAE 仓库 tag,可以临时指定本次打包版本。下面命令会创建一个本地临时脚本,让 CMake 本次配置时读到 `1.1.3`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$Version = "1.1.3"
|
||||||
|
$GitVersionShim = "..\.tmp\git-version-$Version.cmd"
|
||||||
|
New-Item -ItemType Directory -Force (Split-Path $GitVersionShim) | Out-Null
|
||||||
|
|
||||||
|
@"
|
||||||
|
@echo off
|
||||||
|
if /I "%1"=="describe" (
|
||||||
|
echo $Version
|
||||||
|
exit /b 0
|
||||||
|
)
|
||||||
|
git %*
|
||||||
|
"@ | Set-Content -LiteralPath $GitVersionShim -Encoding ASCII
|
||||||
|
```
|
||||||
|
|
||||||
|
后续所有命令都复用这个 `$Version`。不要只改 ZIP 文件名,否则会出现文件名是 `1.1.3`,但组件 `package.xml` 和 `Updates.xml` 里版本还是 `0.10.1` 的错包;这种包上传后,MaintenanceTool 仍然会按 `0.10.1` 判断。
|
||||||
|
|
||||||
|
## 五、刷新现有 CMake 打包配置
|
||||||
|
|
||||||
|
下面命令只刷新已有构建目录的 CMake 配置,用来告诉打包目标 Qt IFW 在哪里,以及 Hub 更新客户端的本地编译产物和 SDK 兜底在哪里,不是全量重新编译 SIMCAE。
|
||||||
|
|
||||||
|
先确认当前 PowerShell 已经在 SIMCAE 项目根目录。下面给出一个常见 Qt IFW 安装路径示例;如果你的 Qt IFW 装在别的位置,只改 `$QtIfwRoot` 这一行。
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$Build = ".\out\build\SimCAE-release-vs2022-qt515-ifw"
|
||||||
|
$QtIfwRoot = "C:\Qt\Tools\QtInstallerFramework\4.11"
|
||||||
|
$HubUpdateClientRuntime = ".\update-client\out\bin\Release"
|
||||||
|
$UpdateClientSdk = ".\update-client\dist\UpdateClientSDK-With-QtDll"
|
||||||
|
```
|
||||||
|
|
||||||
|
先检查 SIMCAE 工程里的 Hub 更新客户端本地编译产物:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-Path "$QtIfwRoot\bin\binarycreator.exe"
|
||||||
|
Test-Path "$QtIfwRoot\bin\repogen.exe"
|
||||||
|
Test-Path "$HubUpdateClientRuntime\Launcher.exe"
|
||||||
|
Test-Path "$HubUpdateClientRuntime\Updater.exe"
|
||||||
|
Test-Path "$HubUpdateClientRuntime\Bootstrap.exe"
|
||||||
|
```
|
||||||
|
|
||||||
|
如果上面三个 EXE 都存在,打 SIMCAE 安装包时会优先使用它们,不会再从 SDK 目录重复拿一份。
|
||||||
|
|
||||||
|
如果本地编译产物不存在,再检查 SDK 兜底目录:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-Path "$UpdateClientSdk\bin\Launcher.exe"
|
||||||
|
Test-Path "$UpdateClientSdk\bin\Updater.exe"
|
||||||
|
Test-Path "$UpdateClientSdk\bin\Bootstrap.exe"
|
||||||
|
```
|
||||||
|
|
||||||
|
如果本次要让 `SimCAE.exe` 只能从 `Launcher.exe` 启动,先准备 SIMCAE 编译期使用的本地打包配置。这里的 `launch_token` 必须和服务端 `.env` 里的 `SIMCAE_LAUNCH_TOKEN` 完全一致。
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$LauncherProductConfig = "..\.tmp\simcae-launcher-product-config.json"
|
||||||
|
|
||||||
|
@'
|
||||||
|
{
|
||||||
|
"app_id": "simcae",
|
||||||
|
"product_code": "simcae",
|
||||||
|
"app_name": "SimCAE",
|
||||||
|
"launch_token": "SimCAE_Launch_Token_2026_ChangeMe_32Bytes",
|
||||||
|
"license_key": "SIMCAE_LOCAL_PACKAGING_LICENSE_2026"
|
||||||
|
}
|
||||||
|
'@ | Set-Content -LiteralPath $LauncherProductConfig -Encoding UTF8
|
||||||
|
```
|
||||||
|
|
||||||
|
刷新配置:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cmake -S . -B $Build `
|
||||||
|
"-DSimCAE_QtIfwRoot=$QtIfwRoot" `
|
||||||
|
"-DSimCAE_PackageHubUpdateClient=ON" `
|
||||||
|
"-DSimCAE_HubUpdateClientRuntimeDir=$HubUpdateClientRuntime" `
|
||||||
|
"-DSimCAE_HubUpdateClientSdkDir=$UpdateClientSdk" `
|
||||||
|
"-DSimCAE_UseLauncher=ON" `
|
||||||
|
"-DSimCAE_LauncherProductConfigFile=$LauncherProductConfig" `
|
||||||
|
"-DGIT_EXECUTABLE=$GitVersionShim"
|
||||||
|
```
|
||||||
|
|
||||||
|
`SimCAE_PackageHubUpdateClient=ON` 只负责把 `Launcher.exe`、`Updater.exe`、`Bootstrap.exe` 放进 SIMCAE 安装包。正式客户配置文件,例如 `config/app_config.json` 和 `config/manifest_public_key.pem`,仍然由服务端在上传发布包时生成或注入,不从开发机本地目录带进最终客户包。
|
||||||
|
|
||||||
|
如果只想把 Hub 更新客户端打进安装包,但暂时不限制用户直接双击 `SimCAE.exe`,则把上面命令中的 `SimCAE_UseLauncher` 改为 `OFF`,并去掉 `SimCAE_LauncherProductConfigFile` 这一项。
|
||||||
|
|
||||||
|
## 六、生成客户安装器和 IFW package
|
||||||
|
|
||||||
|
执行打包目标:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cmake --build $Build --config Release --target package_installer
|
||||||
|
```
|
||||||
|
|
||||||
|
这个目标会读取 `SIMCAE\installer` 下的配置和组件规则,整理 IFW package staging,并生成安装器。组件有哪些、每个组件包含哪些文件、组件是否必选、依赖哪些组件,应该由 SIMCAE 开发者在打包配置和 `package.xml.in` 里提前定义好;SimCAE Hub 不会自动猜测业务应该拆成哪些组件。
|
||||||
|
|
||||||
|
当前示例里已有两个 IFW 组件:
|
||||||
|
|
||||||
|
| 组件目录 | 组件含义 | 元数据来源 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `packages/com.simcae.app` | 核心程序、Launcher、Updater、Bootstrap、核心库和通用资源 | `installer/packages/meta/package.xml.in` |
|
||||||
|
| `packages/com.simcae.dap` | DAP 求解器插件及运行资源 | `installer/packages/com.simcae.dap/meta/package.xml.in` |
|
||||||
|
|
||||||
|
Qt IFW 的组件 ID 来自 `packages/<组件ID>` 目录名,例如 `com.simcae.dap`。组件显示名称、版本、是否强制安装、依赖关系等来自该组件的 `meta/package.xml`,例如 `<DisplayName>`、`<Version>`、`<ForcedInstallation>`、`<Dependencies>`。
|
||||||
|
|
||||||
|
常见输出:
|
||||||
|
|
||||||
|
| 输出 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `$Build\package` | Qt IFW package staging 目录 |
|
||||||
|
| `$Build\SimCAE-<版本>-Windows-installer.exe` | 本地生成的客户安装器 |
|
||||||
|
|
||||||
|
确认核心组件里已经带上 Hub 更新客户端:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-Path "$Build\package\packages\com.simcae.app\data\view\bin\Launcher.exe"
|
||||||
|
Test-Path "$Build\package\packages\com.simcae.app\data\view\bin\Updater.exe"
|
||||||
|
Test-Path "$Build\package\packages\com.simcae.app\data\view\bin\Bootstrap.exe"
|
||||||
|
Test-Path "$Build\package\packages\com.simcae.app\data\view\bin\SimCAE.exe"
|
||||||
|
```
|
||||||
|
|
||||||
|
预期都返回 `True`。
|
||||||
|
|
||||||
|
再确认 package 里的组件版本就是本次 `$Version`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$AppPackageXml = "$Build\package\packages\com.simcae.app\meta\package.xml"
|
||||||
|
$DapPackageXml = "$Build\package\packages\com.simcae.dap\meta\package.xml"
|
||||||
|
$AppVersion = ([xml](Get-Content -LiteralPath $AppPackageXml -Encoding UTF8 -Raw)).Package.Version
|
||||||
|
$DapVersion = ([xml](Get-Content -LiteralPath $DapPackageXml -Encoding UTF8 -Raw)).Package.Version
|
||||||
|
|
||||||
|
if ($AppVersion -ne $Version -or $DapVersion -ne $Version) {
|
||||||
|
throw "组件版本不一致:app=$AppVersion dap=$DapVersion expected=$Version"
|
||||||
|
}
|
||||||
|
|
||||||
|
Test-Path "$Build\SimCAE-$Version-Windows-installer.exe"
|
||||||
|
```
|
||||||
|
|
||||||
|
最后一行预期返回 `True`。如果这里不是 `True`,不要继续生成 repository。
|
||||||
|
|
||||||
|
## 七、生成 IFW repository
|
||||||
|
|
||||||
|
MaintenanceTool 读取的是 Qt IFW repository,不是客户安装器。
|
||||||
|
|
||||||
|
生成前先确认 `$Build\package` 已经存在,并且里面至少有 `config` 和 `packages`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-Path "$Build\package\config\config.xml"
|
||||||
|
Test-Path "$Build\package\packages"
|
||||||
|
```
|
||||||
|
|
||||||
|
预期都返回 `True`。然后生成完整 repository:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File ".\installer\scripts\build-ifw-repository.ps1" `
|
||||||
|
-PackageDir "$Build\package" `
|
||||||
|
-OutputDir "$Build\ifw-repository" `
|
||||||
|
-ZipFile "$Build\SimCAE-IFW-Repository-$Version-windows_x86_64-msvc.zip"
|
||||||
|
```
|
||||||
|
|
||||||
|
这条命令不是“给压缩包打版本标签”。它只是调用 Qt IFW 的 `repogen.exe`,从 `$Build\package\packages` 读取已经准备好的组件目录和 `meta/package.xml`,生成 `Updates.xml` 和组件 `.7z` 包,最后把 repository 目录压成 ZIP。ZIP 文件名里的 `$Version` 只是为了让发布人员识别文件。
|
||||||
|
|
||||||
|
生成后检查:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-Path "$Build\ifw-repository\Updates.xml"
|
||||||
|
Select-String -LiteralPath "$Build\ifw-repository\Updates.xml" -Pattern "com.simcae.app|com.simcae.dap|<Version>"
|
||||||
|
```
|
||||||
|
|
||||||
|
生成的 repository 根目录必须包含 `Updates.xml`。这个 ZIP 一般不直接给客户,它是给 SimCAE Hub 后端托管,供 `maintenancetool.exe` 后续检查组件更新。
|
||||||
|
|
||||||
|
确认 repository 里的组件版本也是本次 `$Version`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$UpdatesXml = "$Build\ifw-repository\Updates.xml"
|
||||||
|
$UpdatesContent = Get-Content -LiteralPath $UpdatesXml -Encoding UTF8 -Raw
|
||||||
|
|
||||||
|
if ($UpdatesContent -notmatch "<Version>$([regex]::Escape($Version))</Version>") {
|
||||||
|
throw "repository Updates.xml 中没有本次版本 $Version"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 八、组装 Qt IFW 交付包 ZIP
|
||||||
|
|
||||||
|
推荐上传给 SimCAE Hub 的是交付包 ZIP,它把 package 和 repository 放在一起。客户安装器由服务端基于注入配置后的 package 重新生成。
|
||||||
|
|
||||||
|
目录结构建议:
|
||||||
|
|
||||||
|
- `package/config/`
|
||||||
|
- `package/packages/com.simcae.app/`
|
||||||
|
- `package/packages/com.simcae.dap/`
|
||||||
|
- `repository/Updates.xml`
|
||||||
|
- `repository/com.simcae.app/`
|
||||||
|
- `repository/com.simcae.dap/`
|
||||||
|
|
||||||
|
不要依赖交付包里的 `installer/SimCAE-<版本>-Windows-installer.exe` 作为最终客户安装器。本地生成的安装器没有服务端注入的 `app_config.json`,客户直接安装后 `Launcher.exe` 会缺少服务器地址、token 和主程序配置。服务端必须配置 `SIMCAE_IFW_BINARYCREATOR_PATH`,Linux 服务端生成 Windows 安装器时还必须配置 `SIMCAE_IFW_INSTALLERBASE_WINDOWS_PATH` 指向 Windows 版 `installerbase.exe`,上传后由服务端重新生成客户门户可下载的安装器。
|
||||||
|
|
||||||
|
示例命令:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$PlatformKey = "windows_x86_64-msvc"
|
||||||
|
$Bundle = "$Build\SimCAE-Delivery-$Version-$PlatformKey"
|
||||||
|
|
||||||
|
if (-not (Test-Path "$Build\ifw-repository\Updates.xml")) {
|
||||||
|
throw "缺少 repository/Updates.xml,请先生成 IFW repository"
|
||||||
|
}
|
||||||
|
|
||||||
|
Remove-Item -LiteralPath $Bundle -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
New-Item -ItemType Directory -Force "$Bundle" | Out-Null
|
||||||
|
|
||||||
|
Copy-Item "$Build\package" "$Bundle\package" -Recurse -Force
|
||||||
|
Copy-Item "$Build\ifw-repository" "$Bundle\repository" -Recurse -Force
|
||||||
|
|
||||||
|
Compress-Archive -Path "$Bundle\*" -DestinationPath "$Build\SimCAE-Delivery-$Version-$PlatformKey.zip" -Force
|
||||||
|
```
|
||||||
|
|
||||||
|
`release.json` 不需要开发者手写。产品编码、产品名称、版本号、通道、平台、架构和 ABI 来自管理后台表单;运行目录和主程序名由服务端从核心组件中自动识别。
|
||||||
|
|
||||||
|
## 九、上传到管理后台
|
||||||
|
|
||||||
|
在浏览器打开管理后台,例如 `http://192.168.1.158:1798/login`。
|
||||||
|
|
||||||
|
按左侧菜单顺序准备基础数据。第一次发布某个产品时要完整走一遍;后续同产品、同通道、同平台发布新版本时,只需要确认这些数据仍然存在:
|
||||||
|
|
||||||
|
1. 产品目录:确认产品编码,例如 `simcae`。
|
||||||
|
2. 版本线:确认通道或版本线,例如 `stable`。
|
||||||
|
3. 组件管理:确认核心组件和可选组件,例如 `com.simcae.app`、`com.simcae.dap`;如果用于 MaintenanceTool 更新,后台组件编码要和 IFW package 的 `packages/<组件ID>` 目录名一致。
|
||||||
|
4. 平台管理:确认 `windows`、`x86_64`、`msvc`。
|
||||||
|
5. 产品版本:创建本次版本,例如 `1.1.3`。
|
||||||
|
6. 软件发布:创建本次发布,关联产品版本和版本线。
|
||||||
|
7. 发布包:新增或编辑发布包。
|
||||||
|
|
||||||
|
上传完整 Qt IFW 交付包时,在“发布包”页面直接点击右上角新增发布包,不需要先点击某个软件卡片。这个入口只用于新建整包更新包和 Qt IFW 交付包。
|
||||||
|
|
||||||
|
发布包页面选择:
|
||||||
|
|
||||||
|
| 字段 | 建议 |
|
||||||
|
| --- | --- |
|
||||||
|
| 包类型 | Qt IFW 交付包 |
|
||||||
|
| 文件 | `SimCAE-Delivery-<版本>-windows_x86_64-msvc.zip` |
|
||||||
|
| 平台 | `windows / x86_64 / msvc` |
|
||||||
|
| 状态 | 上传校验通过后变为可用 |
|
||||||
|
|
||||||
|
操作顺序:
|
||||||
|
|
||||||
|
1. 打开“发布包”页面。
|
||||||
|
2. 直接点击右上角“新建发布包”。
|
||||||
|
3. 包类型选择“Qt IFW 交付包”。此时普通新建入口只应看到“整包更新包”和“Qt IFW 交付包”。
|
||||||
|
4. 文件名填写本次交付包文件名,例如 `SimCAE-Delivery-1.1.3-windows_x86_64-msvc.zip`。
|
||||||
|
5. 选择产品、版本线、产品版本、发布和平台。
|
||||||
|
6. 保存发布包记录。
|
||||||
|
7. 点击该记录的“上传”。
|
||||||
|
8. 选择本地生成的交付包 ZIP。
|
||||||
|
9. 等待上传完成,状态应变为“可用”。
|
||||||
|
|
||||||
|
上传成功后,服务端会:
|
||||||
|
|
||||||
|
- 校验 ZIP 安全路径和 IFW 结构。
|
||||||
|
- 校验 `package/` 和 `repository/Updates.xml`。
|
||||||
|
- 读取组件清单和组件版本。
|
||||||
|
- 自动注入 `config/app_config.json`。
|
||||||
|
- 自动写入必要的公钥配置。
|
||||||
|
- 发布 IFW repository。
|
||||||
|
- 生成或登记客户门户首次下载的安装器。
|
||||||
|
|
||||||
|
上传后建议立刻确认:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$Base = "http://192.168.1.158:18000/api/v1/client/ifw/repositories/simcae/stable/windows_x86_64-msvc"
|
||||||
|
(Invoke-WebRequest "$Base/Updates.xml" -UseBasicParsing).Content
|
||||||
|
```
|
||||||
|
|
||||||
|
预期能看到本次版本号、组件 ID 和组件名称。如果这里还是旧版本,先确认发布包状态是否为“可用”,再确认上传时选择的产品、通道和平台是否一致。
|
||||||
|
|
||||||
|
## 十、客户下载和安装
|
||||||
|
|
||||||
|
客户登录客户门户后,在下载中心下载客户安装器。客户下载到的是 `.exe` 安装器,不是 IFW repository ZIP,也不是开发者上传的交付包 ZIP。
|
||||||
|
|
||||||
|
客户安装后,安装目录中应包含:
|
||||||
|
|
||||||
|
- `maintenancetool.exe`
|
||||||
|
- `components.xml`
|
||||||
|
- `network.xml`
|
||||||
|
- `view\bin\SimCAE.exe`
|
||||||
|
- `view\bin\Launcher.exe`
|
||||||
|
- `view\bin\Updater.exe`
|
||||||
|
- `view\bin\Bootstrap.exe`
|
||||||
|
- `view\bin\config\app_config.json`
|
||||||
|
|
||||||
|
客户日常启动软件应使用 `Launcher.exe` 或安装器创建的快捷方式。组件更新、添加、移除由 `maintenancetool.exe` 负责。
|
||||||
|
|
||||||
|
首次安装建议按这个顺序检查:
|
||||||
|
|
||||||
|
1. 打开客户门户。
|
||||||
|
2. 登录有授权的客户账号。
|
||||||
|
3. 进入下载中心。
|
||||||
|
4. 找到对应产品和版本。
|
||||||
|
5. 点击下载,得到 `SimCAE-<版本>-Windows-installer.exe`。
|
||||||
|
6. 双击安装器,按页面提示完成安装。
|
||||||
|
7. 安装后进入安装目录,确认 `maintenancetool.exe`、`components.xml` 和 `view\bin\Launcher.exe` 都存在。
|
||||||
|
8. 双击 `Launcher.exe`,预期能启动 SimCAE。
|
||||||
|
9. 双击 `maintenancetool.exe`,预期能看到“添加或移除组件”“更新组件”“移除所有组件”。
|
||||||
|
|
||||||
|
## 十一、组件更新
|
||||||
|
|
||||||
|
这里的“组件”指 `maintenancetool.exe` 里能看到的 Qt IFW 组件,例如 `com.simcae.app`、`com.simcae.dap`。组件更新就是“只发布某些组件的新版本,或新增一个组件”,让客户后续通过 MaintenanceTool 更新;它不是客户首次安装用的安装器,也不是 Launcher / Updater 用的整包更新 ZIP。
|
||||||
|
|
||||||
|
适合使用组件更新的情况:
|
||||||
|
|
||||||
|
| 场景 | 应该怎么做 |
|
||||||
|
| --- | --- |
|
||||||
|
| 只更新 DAP 插件 | 做一个只包含 `com.simcae.dap` 的组件更新包 |
|
||||||
|
| 新增示例、模板、插件等可选功能 | 做一个包含新组件的组件更新包 |
|
||||||
|
| 一次更新几个互相依赖的组件 | 做一个多组件更新包,把这些组件一起放进去 |
|
||||||
|
| 更新核心程序、Launcher、Updater、Bootstrap 或 `app_config.json` | 更推荐重新发完整 Qt IFW 交付包 |
|
||||||
|
| 第一次发布某个产品、通道、平台 | 先发完整 Qt IFW 交付包,后面才能发组件更新 |
|
||||||
|
|
||||||
|
组件更新包不是单独飘在系统外面的文件。它上传时必须挂到某个产品、某个产品版本、某次发布、某个平台下面。服务端会把它合并到这个产品对应通道和平台的 current repository 中。
|
||||||
|
|
||||||
|
### 11.1 组件版本怎么定
|
||||||
|
|
||||||
|
组件版本以组件自己的 `package.xml` 为准。比如 DAP 组件的版本写在这里:
|
||||||
|
|
||||||
|
- `$Build\package\packages\com.simcae.dap\meta\package.xml`
|
||||||
|
- XML 节点是 `<Version>1.1.4</Version>`
|
||||||
|
|
||||||
|
如果说“组件标签”,这里真正参与更新判断的是组件 ID 和组件版本:组件 ID 来自目录名 `packages/com.simcae.dap`,组件版本来自 `meta/package.xml` 里的 `<Version>`。开发者在维护 IFW package 时就应该把组件拆分、显示名、版本、必选状态和依赖关系写清楚。`repogen.exe` 生成 repository 时,会把这些信息写进 `Updates.xml`。MaintenanceTool 也是根据 `Updates.xml` 里的组件版本判断是否可更新。
|
||||||
|
|
||||||
|
当前 SIMCAE 全量打包默认会让所有组件跟随同一个 `$Version`,这个 `$Version` 来自 SIMCAE 仓库的纯数字 Git tag,或者前面文档里的 `$GitVersionShim` 临时版本脚本。例如 `$Version = "1.1.3"` 时,`com.simcae.app` 和 `com.simcae.dap` 默认都会变成 `1.1.3`。
|
||||||
|
|
||||||
|
如果只更新 DAP,不更新核心组件,规则是:
|
||||||
|
|
||||||
|
1. 服务器当前 `com.simcae.app` 是 `1.1.3`,`com.simcae.dap` 是 `1.1.3`。
|
||||||
|
2. 本次只把 `com.simcae.dap` 的 `package.xml` 改成 `1.1.4`。
|
||||||
|
3. 不改 `com.simcae.app` 的 `package.xml`,它仍然保持 `1.1.3`。
|
||||||
|
4. 生成只包含 `com.simcae.dap` 的组件更新包。
|
||||||
|
5. 上传后,服务器 current repository 里应变成 `com.simcae.app=1.1.3`、`com.simcae.dap=1.1.4`。
|
||||||
|
|
||||||
|
正式流程里,建议 SIMCAE 打包侧给每个组件提供独立版本参数。当前如果只是本地演示,可以在 `$Build\package\packages\<组件ID>\meta\package.xml` 里调整目标组件的 `<Version>`,然后再生成组件更新包。不要改不更新的组件版本,也不要只改 ZIP 文件名。ZIP 名字里写了 `1.1.4`,但 `package.xml` 仍是 `1.1.3` 时,生成出来的 `Updates.xml` 也会是 `1.1.3`。
|
||||||
|
|
||||||
|
### 11.2 先确认服务器已有当前仓库
|
||||||
|
|
||||||
|
以 `simcae / stable / windows_x86_64-msvc` 为例:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$Base = "http://192.168.1.158:18000/api/v1/client/ifw/repositories/simcae/stable/windows_x86_64-msvc"
|
||||||
|
(Invoke-WebRequest "$Base/Updates.xml" -UseBasicParsing).Content
|
||||||
|
```
|
||||||
|
|
||||||
|
预期能看到当前仓库的组件,例如:
|
||||||
|
|
||||||
|
- `<Name>com.simcae.app</Name>`
|
||||||
|
- `<Version>1.1.3</Version>`
|
||||||
|
- `<Name>com.simcae.dap</Name>`
|
||||||
|
- `<Version>1.1.3</Version>`
|
||||||
|
|
||||||
|
如果这里访问失败,先不要上传组件更新包,说明服务器还没有这个产品、通道、平台的 current repository。
|
||||||
|
|
||||||
|
### 11.3 准备本地组件产物
|
||||||
|
|
||||||
|
开发者先按 SIMCAE 自己的规则把组件文件准备到 IFW package staging 里。组件边界应该在开发和打包配置阶段就已经分好;后面的 repository 生成命令只是读取这些组件,不会自动分析文件并替开发者拆组件。当前打包目标会把组件整理到:
|
||||||
|
|
||||||
|
- `$Build\package\packages\com.simcae.app`
|
||||||
|
- `$Build\package\packages\com.simcae.dap`
|
||||||
|
|
||||||
|
如果只更新 DAP 插件,先确认 DAP 组件目录存在:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-Path "$Build\package\packages\com.simcae.dap\meta\package.xml"
|
||||||
|
Test-Path "$Build\package\packages\com.simcae.dap\data"
|
||||||
|
```
|
||||||
|
|
||||||
|
预期都返回 `True`。同时要确认 `package.xml` 里的版本已经升高:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Select-String -LiteralPath "$Build\package\packages\com.simcae.dap\meta\package.xml" -Pattern "<Version>"
|
||||||
|
```
|
||||||
|
|
||||||
|
例如服务器当前 DAP 是 `1.1.3`,本次 DAP 组件更新包应改成 `1.1.4` 或更高。
|
||||||
|
|
||||||
|
### 11.4 生成组件更新 ZIP
|
||||||
|
|
||||||
|
使用 `-Include` 只把要更新的组件打进 repository。`-Include "com.simcae.dap"` 里的值是组件 ID,也就是 `packages/com.simcae.dap` 这个目录名;它不是 ZIP 标签,也不是版本号。下面以只更新 DAP 为例:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$ComponentVersion = "1.1.4"
|
||||||
|
$PlatformKey = "windows_x86_64-msvc"
|
||||||
|
$ComponentUpdateRepository = "$Build\ifw-component-update-com.simcae.dap-$ComponentVersion"
|
||||||
|
$ComponentUpdateZip = "$Build\SimCAE-IFW-ComponentUpdate-com.simcae.dap-$ComponentVersion-$PlatformKey.zip"
|
||||||
|
|
||||||
|
Remove-Item -LiteralPath $ComponentUpdateRepository -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File ".\installer\scripts\build-ifw-repository.ps1" `
|
||||||
|
-PackageDir "$Build\package" `
|
||||||
|
-OutputDir $ComponentUpdateRepository `
|
||||||
|
-ZipFile $ComponentUpdateZip `
|
||||||
|
-Include "com.simcae.dap"
|
||||||
|
```
|
||||||
|
|
||||||
|
这条命令不会修改 `com.simcae.dap` 的 `<Version>`。它只是根据 `-Include` 选择已有组件,把该组件当前 `package.xml` 中写好的版本、显示名和依赖交给 `repogen.exe`,再生成本次组件更新 repository ZIP。
|
||||||
|
|
||||||
|
如果一次更新多个组件:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File ".\installer\scripts\build-ifw-repository.ps1" `
|
||||||
|
-PackageDir "$Build\package" `
|
||||||
|
-OutputDir "$Build\ifw-component-update-multi-$ComponentVersion" `
|
||||||
|
-ZipFile "$Build\SimCAE-IFW-ComponentUpdate-multi-$ComponentVersion-$PlatformKey.zip" `
|
||||||
|
-Include "com.simcae.app","com.simcae.dap"
|
||||||
|
```
|
||||||
|
|
||||||
|
生成后检查 ZIP 对应的展开目录:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Test-Path "$ComponentUpdateRepository\Updates.xml"
|
||||||
|
Get-ChildItem -LiteralPath $ComponentUpdateRepository
|
||||||
|
Select-String -LiteralPath "$ComponentUpdateRepository\Updates.xml" -Pattern "com.simcae.dap|<Version>|<Dependencies>"
|
||||||
|
```
|
||||||
|
|
||||||
|
单 DAP 更新包的典型结构应类似:
|
||||||
|
|
||||||
|
- `Updates.xml`
|
||||||
|
- `com.simcae.dap/1.1.4meta.7z`
|
||||||
|
- `com.simcae.dap/1.1.4view.7z`
|
||||||
|
- `com.simcae.dap/1.1.4view.7z.sha1`
|
||||||
|
|
||||||
|
如果 ZIP 解开后外面多套了一层目录,也可以上传;服务端会识别常见外层目录。但推荐让 ZIP 根部直接就是 `Updates.xml` 和组件目录,最不容易出错。
|
||||||
|
|
||||||
|
### 11.5 上传组件更新
|
||||||
|
|
||||||
|
管理后台操作:
|
||||||
|
|
||||||
|
1. 打开“产品版本”,创建本次发布批次版本,例如 `1.1.4`。
|
||||||
|
2. 打开“软件发布”,创建本次发布,通道仍选择 `stable`。
|
||||||
|
3. 打开“发布包”,先点击要更新的软件卡片,进入该软件的发布包视图。
|
||||||
|
4. 点击“新建组件更新包”。进入某个软件后,包类型固定为“组件更新”,产品固定为当前软件。
|
||||||
|
5. 发布选择刚创建的 `1.1.4` 发布。
|
||||||
|
6. 平台选择和 current repository 完全一致的 `windows / x86_64 / msvc`。
|
||||||
|
7. 文件名填写 `SimCAE-IFW-ComponentUpdate-com.simcae.dap-1.1.4-windows_x86_64-msvc.zip`。
|
||||||
|
8. 保存后点击“上传”。
|
||||||
|
9. 选择上一步生成的 `$ComponentUpdateZip`。
|
||||||
|
10. 上传成功后,发布包状态应变为“可用”。
|
||||||
|
|
||||||
|
上传成功后,服务端会把更新组件合并进 current repository,未变化组件保持不变。
|
||||||
|
|
||||||
|
### 11.6 上传后确认合并结果
|
||||||
|
|
||||||
|
重新读取服务器仓库:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$Base = "http://192.168.1.158:18000/api/v1/client/ifw/repositories/simcae/stable/windows_x86_64-msvc"
|
||||||
|
(Invoke-WebRequest "$Base/Updates.xml" -UseBasicParsing).Content
|
||||||
|
```
|
||||||
|
|
||||||
|
预期:
|
||||||
|
|
||||||
|
1. 更新过的组件版本变成新版本,例如 `com.simcae.dap` 是 `1.1.4`。
|
||||||
|
2. 未更新的组件仍然存在,例如 `com.simcae.app` 还在。
|
||||||
|
3. 新增组件能出现在 `Updates.xml` 中。
|
||||||
|
4. 旧版本仓库仍保存在服务端 `releases/<版本>` 目录中,current 指向最新合并结果。
|
||||||
|
|
||||||
|
### 11.7 常见失败提示
|
||||||
|
|
||||||
|
| 提示含义 | 原因 | 处理 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 当前产品、通道和平台下还没有可合并的 IFW 当前仓库 | 还没上传过完整交付包 | 先上传完整 Qt IFW 交付包 |
|
||||||
|
| 组件版本不能倒退或重复 | 上传组件版本小于或等于服务器 current 版本 | 升高组件 `package.xml` 里的版本后重新生成 |
|
||||||
|
| 组件依赖不存在 | 新组件依赖的组件不在 current 仓库,也不在本次包里 | 先发布依赖组件,或把依赖组件一起打进本次更新包 |
|
||||||
|
| 缺少组件目录 | `Updates.xml` 声明了组件,但 ZIP 里没有对应目录 | 重新用 `build-ifw-repository.ps1` 生成 |
|
||||||
|
| 包含未在 `Updates.xml` 声明的组件目录 | ZIP 里多了未声明目录 | 删除多余目录后重新压包 |
|
||||||
|
| 未包含 `Updates.xml` | 上传的不是 repository ZIP,或服务端没有配置 `SIMCAE_IFW_REPOGEN_PATH` 来从 packages 自动生成 | 上传 repository 形态 ZIP |
|
||||||
|
|
||||||
|
更新包失败时,服务端不会破坏原 current repository。
|
||||||
|
|
||||||
|
## 十二、换源
|
||||||
|
|
||||||
|
服务器地址变化时有两种处理方式:
|
||||||
|
|
||||||
|
| 方式 | 适用场景 |
|
||||||
|
| --- | --- |
|
||||||
|
| 临时换源命令 | 单台客户机器临时切到新仓库 |
|
||||||
|
| RepositoryUpdate 批量换源 | 已安装客户软件批量迁移仓库地址 |
|
||||||
|
|
||||||
|
换源只影响 `maintenancetool.exe` 访问 IFW repository。Launcher / Updater 的 API 地址来自服务端注入的 `app_config.json`,需要通过新发布包或重新安装包更新。
|
||||||
|
|
||||||
|
### 12.1 临时换源
|
||||||
|
|
||||||
|
临时换源适合开发、测试、临时排查。它不会永久改安装包里的默认源。
|
||||||
|
|
||||||
|
在 SIMCAE 项目根目录执行,假设客户软件安装在 `.tmp\maintenance-installed\SimCAE`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$Install = ".\.tmp\maintenance-installed\SimCAE"
|
||||||
|
$Repo = "http://192.168.1.158:18000/api/v1/client/ifw/repositories/simcae/stable/windows_x86_64-msvc/"
|
||||||
|
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File ".\installer\scripts\switch-maintenance-repository.ps1" `
|
||||||
|
-MaintenanceToolPath "$Install\maintenancetool.exe" `
|
||||||
|
-RepositoryUrl $Repo `
|
||||||
|
-Mode Temp `
|
||||||
|
-Command check-updates `
|
||||||
|
-ClearCache
|
||||||
|
```
|
||||||
|
|
||||||
|
注意 `$Repo` 必须是仓库根地址,不能写到 `Updates.xml`:
|
||||||
|
|
||||||
|
- 正确:`http://192.168.1.158:18000/api/v1/client/ifw/repositories/simcae/stable/windows_x86_64-msvc/`
|
||||||
|
- 错误:`http://192.168.1.158:18000/api/v1/client/ifw/repositories/simcae/stable/windows_x86_64-msvc/Updates.xml`
|
||||||
|
|
||||||
|
### 12.2 批量换源
|
||||||
|
|
||||||
|
批量换源适合服务器域名或 IP 变更。做法是在下一次 repository 的 `Updates.xml` 里加入 `RepositoryUpdate`,让 MaintenanceTool 更新组件时顺便替换本机源地址。
|
||||||
|
|
||||||
|
示例:把旧源 `http://192.168.1.158:18000/...` 替换为新源 `https://download.simcae.example.com/...`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$UpdatesXml = "$Build\ifw-repository\Updates.xml"
|
||||||
|
$OldRepo = "http://192.168.1.158:18000/api/v1/client/ifw/repositories/simcae/stable/windows_x86_64-msvc/"
|
||||||
|
$NewRepo = "https://download.simcae.example.com/api/v1/client/ifw/repositories/simcae/stable/windows_x86_64-msvc/"
|
||||||
|
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File ".\installer\scripts\write-repository-update.ps1" `
|
||||||
|
-UpdatesXml $UpdatesXml `
|
||||||
|
-Action replace `
|
||||||
|
-OldUrl $OldRepo `
|
||||||
|
-NewUrl $NewRepo `
|
||||||
|
-DisplayName "SimCAE stable component repository" `
|
||||||
|
-ClearExisting
|
||||||
|
```
|
||||||
|
|
||||||
|
写入后重新压 repository 或重新组装 Qt IFW 交付包,再上传到 SimCAE Hub。客户下一次通过 MaintenanceTool 检查或更新组件后,会把仓库地址换成新地址。
|
||||||
|
|
||||||
|
## 十三、常见问题
|
||||||
|
|
||||||
|
| 现象 | 原因和处理 |
|
||||||
|
| --- | --- |
|
||||||
|
| 上传提示缺少 `Updates.xml` | 选择的不是 repository 或交付包结构不对 |
|
||||||
|
| MaintenanceTool 看不到更新 | 服务器仓库版本没有高于本机 `components.xml` 里的版本 |
|
||||||
|
| 客户下载不到安装器 | 发布包不是 Qt IFW 交付包,或客户安装器生成/登记失败 |
|
||||||
|
| Launcher 启动主程序失败 | `SIMCAE_LAUNCH_TOKEN` 和业务主程序编译时 token 不一致 |
|
||||||
|
| 直接双击 `SimCAE.exe` 被拦截 | 这是启用 Launcher 启动门禁后的预期行为 |
|
||||||
|
| 可选组件删除后 Updater 报缺文件 | Manifest 中可选组件文件没有标为可选,或组件边界划分不对 |
|
||||||
+4
-5
@@ -25,9 +25,8 @@ SimCAE Hub 的 Go API。
|
|||||||
|
|
||||||
SDK 打包命令、两种打包模式、参数含义和输出位置,统一看:
|
SDK 打包命令、两种打包模式、参数含义和输出位置,统一看:
|
||||||
|
|
||||||
../打包成SDK.md
|
../updater打包成SDK.md
|
||||||
|
|
||||||
生成 SDK 后,把 Launcher、Updater、Bootstrap 和必要运行库放进业务软件
|
生成 SDK 后,SDK 根目录里只带给 SIMCAE 发布人员看的 SIMCAE打包上传.md。
|
||||||
根目录或 bin 目录,再把完整软件目录压缩上传到 SimCAE Hub 管理后台的
|
后续如何把 Launcher、Updater、Bootstrap 和必要运行库放进业务软件、如何
|
||||||
发布包页面。服务端会生成 config/app_config.json,并在启用 Manifest 签名
|
组装 Qt IFW 交付包并上传,以该文档为准。
|
||||||
时生成 config/manifest_public_key.pem。
|
|
||||||
|
|||||||
+11
-20
@@ -10,14 +10,15 @@ param(
|
|||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
$RepoRoot = Split-Path -Parent $PSScriptRoot
|
$RepoRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
$DefaultSdkName = if ($IncludeQtRuntime) { "UpdateClientSDK-With-QtDll" } else { "UpdateClientSDK" }
|
||||||
if ([string]::IsNullOrWhiteSpace($SourceDir)) {
|
if ([string]::IsNullOrWhiteSpace($SourceDir)) {
|
||||||
$SourceDir = Join-Path $RepoRoot "out/bin/Release"
|
$SourceDir = Join-Path $RepoRoot "out/bin/Release"
|
||||||
}
|
}
|
||||||
if ([string]::IsNullOrWhiteSpace($OutputDir)) {
|
if ([string]::IsNullOrWhiteSpace($OutputDir)) {
|
||||||
$OutputDir = Join-Path $RepoRoot "dist/SimCAEHubUpdateClientSDK"
|
$OutputDir = Join-Path $RepoRoot "dist/$DefaultSdkName"
|
||||||
}
|
}
|
||||||
if ([string]::IsNullOrWhiteSpace($ZipFile)) {
|
if ([string]::IsNullOrWhiteSpace($ZipFile)) {
|
||||||
$ZipFile = Join-Path $RepoRoot "dist/SimCAEHubUpdateClientSDK.zip"
|
$ZipFile = Join-Path $RepoRoot "dist/$DefaultSdkName.zip"
|
||||||
}
|
}
|
||||||
|
|
||||||
$source = (Resolve-Path $SourceDir).Path
|
$source = (Resolve-Path $SourceDir).Path
|
||||||
@@ -45,8 +46,7 @@ $binDir = Join-Path $OutputDir "bin"
|
|||||||
$configDir = Join-Path $OutputDir "config"
|
$configDir = Join-Path $OutputDir "config"
|
||||||
$scriptsDir = Join-Path $OutputDir "scripts"
|
$scriptsDir = Join-Path $OutputDir "scripts"
|
||||||
$commonDir = Join-Path $OutputDir "Common"
|
$commonDir = Join-Path $OutputDir "Common"
|
||||||
$docsDir = Join-Path $OutputDir "Docs"
|
New-Item $binDir,$configDir,$scriptsDir,$commonDir -ItemType Directory -Force | Out-Null
|
||||||
New-Item $binDir,$configDir,$scriptsDir,$commonDir,$docsDir -ItemType Directory -Force | Out-Null
|
|
||||||
|
|
||||||
$excludedTopLevel = @("config", "update", "update_temp", "manifest_public_key.pem")
|
$excludedTopLevel = @("config", "update", "update_temp", "manifest_public_key.pem")
|
||||||
if (-not $IncludeDemoMainApp) { $excludedTopLevel += "MainApp.exe" }
|
if (-not $IncludeDemoMainApp) { $excludedTopLevel += "MainApp.exe" }
|
||||||
@@ -108,21 +108,12 @@ foreach ($commonFile in $commonSourceFiles) {
|
|||||||
Copy-Item $commonPath (Join-Path $commonDir $commonFile) -Force
|
Copy-Item $commonPath (Join-Path $commonDir $commonFile) -Force
|
||||||
}
|
}
|
||||||
|
|
||||||
$docsSourceDir = Join-Path $RepoRoot "Docs"
|
$sdkGuideName = [string]::Concat("SIMCAE", [char]0x6253, [char]0x5305, [char]0x4e0a, [char]0x4f20, ".md")
|
||||||
if (Test-Path $docsSourceDir) {
|
$sdkGuideSource = Join-Path $RepoRoot $sdkGuideName
|
||||||
Copy-Item (Join-Path $docsSourceDir "*") $docsDir -Recurse -Force
|
if (Test-Path $sdkGuideSource) {
|
||||||
}
|
Copy-Item $sdkGuideSource (Join-Path $OutputDir $sdkGuideName) -Force
|
||||||
|
|
||||||
$wordGuideSource = @($RepoRoot, $docsSourceDir) |
|
|
||||||
Where-Object { Test-Path $_ } |
|
|
||||||
ForEach-Object { Get-ChildItem $_ -File -Filter "*.docx" } |
|
|
||||||
Where-Object { $_.Name -like "*SDK*.docx" -and $_.Name -notlike "~$*" } |
|
|
||||||
Sort-Object Name |
|
|
||||||
Select-Object -First 1
|
|
||||||
if ($wordGuideSource) {
|
|
||||||
Copy-Item $wordGuideSource.FullName (Join-Path $OutputDir $wordGuideSource.Name) -Force
|
|
||||||
} else {
|
} else {
|
||||||
Write-Warning "SDK Word guide is missing. Continue packaging with Markdown documents in Docs/."
|
throw "SIMCAE packaging guide is missing: $sdkGuideSource"
|
||||||
}
|
}
|
||||||
|
|
||||||
Copy-Item (Join-Path $PSScriptRoot "package-client.ps1") (Join-Path $scriptsDir "package-client.ps1") -Force
|
Copy-Item (Join-Path $PSScriptRoot "package-client.ps1") (Join-Path $scriptsDir "package-client.ps1") -Force
|
||||||
@@ -137,8 +128,8 @@ Copy-Item (Join-Path $PSScriptRoot "install-sdk.ps1") (Join-Path $scriptsDir "in
|
|||||||
contains_demo_main_app = [bool]$IncludeDemoMainApp
|
contains_demo_main_app = [bool]$IncludeDemoMainApp
|
||||||
contains_qt_runtime = [bool]$IncludeQtRuntime
|
contains_qt_runtime = [bool]$IncludeQtRuntime
|
||||||
contains_final_config = $false
|
contains_final_config = $false
|
||||||
docs_entry = "Docs/01-客户端接入打包部署指南.md"
|
docs_entry = $sdkGuideName
|
||||||
word_guide_included = [bool]$wordGuideSource
|
word_guide_included = $false
|
||||||
integration_sources = $commonSourceFiles
|
integration_sources = $commonSourceFiles
|
||||||
} | ConvertTo-Json -Depth 3 | Set-Content (Join-Path $OutputDir "sdk_manifest.json") -Encoding UTF8
|
} | ConvertTo-Json -Depth 3 | Set-Content (Join-Path $OutputDir "sdk_manifest.json") -Encoding UTF8
|
||||||
|
|
||||||
|
|||||||
+13
-17
@@ -5,8 +5,8 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
|
||||||
SOURCE_DIR="$REPO_ROOT/out/linux/bin"
|
SOURCE_DIR="$REPO_ROOT/out/linux/bin"
|
||||||
OUTPUT_DIR="$REPO_ROOT/dist/SimCAEHubUpdateClientSDK-linux"
|
OUTPUT_DIR="$REPO_ROOT/dist/UpdateClientSDK-linux"
|
||||||
ARCHIVE_FILE="$REPO_ROOT/dist/SimCAEHubUpdateClientSDK-linux.tar.gz"
|
ARCHIVE_FILE="$REPO_ROOT/dist/UpdateClientSDK-linux.tar.gz"
|
||||||
SDK_VERSION="0.1.0"
|
SDK_VERSION="0.1.0"
|
||||||
INCLUDE_DEMO_MAIN_APP=0
|
INCLUDE_DEMO_MAIN_APP=0
|
||||||
INCLUDE_QT_RUNTIME=0
|
INCLUDE_QT_RUNTIME=0
|
||||||
@@ -17,8 +17,8 @@ Usage: package-sdk.sh [options]
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
--source-dir DIR Linux Release output directory. Default: ./out/linux/bin
|
--source-dir DIR Linux Release output directory. Default: ./out/linux/bin
|
||||||
--output-dir DIR SDK directory to generate. Default: ./dist/SimCAEHubUpdateClientSDK-linux
|
--output-dir DIR SDK directory to generate. Default: ./dist/UpdateClientSDK-linux
|
||||||
--archive FILE SDK tar.gz path. Default: ./dist/SimCAEHubUpdateClientSDK-linux.tar.gz
|
--archive FILE SDK tar.gz path. Default: ./dist/UpdateClientSDK-linux.tar.gz
|
||||||
--sdk-version VERSION SDK version. Default: 0.1.0
|
--sdk-version VERSION SDK version. Default: 0.1.0
|
||||||
--include-demo-mainapp Include MainApp demo executable in SDK bin.
|
--include-demo-mainapp Include MainApp demo executable in SDK bin.
|
||||||
--include-qt-runtime Include Qt runtime files from the Release output directory.
|
--include-qt-runtime Include Qt runtime files from the Release output directory.
|
||||||
@@ -58,7 +58,7 @@ if [[ -n "$DEBUG_ARTIFACT" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf "$OUTPUT_DIR"
|
rm -rf "$OUTPUT_DIR"
|
||||||
mkdir -p "$OUTPUT_DIR/bin" "$OUTPUT_DIR/config" "$OUTPUT_DIR/scripts" "$OUTPUT_DIR/Common" "$OUTPUT_DIR/Docs"
|
mkdir -p "$OUTPUT_DIR/bin" "$OUTPUT_DIR/config" "$OUTPUT_DIR/scripts" "$OUTPUT_DIR/Common"
|
||||||
|
|
||||||
is_qt_runtime_item() {
|
is_qt_runtime_item() {
|
||||||
local base="$1"
|
local base="$1"
|
||||||
@@ -103,17 +103,13 @@ for common_file in ConfigHelper.h ConfigHelper.cpp IntegrityHelper.h IntegrityHe
|
|||||||
cp "$common_path" "$OUTPUT_DIR/Common/$common_file"
|
cp "$common_path" "$OUTPUT_DIR/Common/$common_file"
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -d "$REPO_ROOT/Docs" ]]; then
|
SDK_GUIDE_NAME="SIMCAE打包上传.md"
|
||||||
cp -a "$REPO_ROOT/Docs/." "$OUTPUT_DIR/Docs/"
|
SDK_GUIDE_SOURCE="$REPO_ROOT/$SDK_GUIDE_NAME"
|
||||||
fi
|
if [[ -f "$SDK_GUIDE_SOURCE" ]]; then
|
||||||
|
cp "$SDK_GUIDE_SOURCE" "$OUTPUT_DIR/$SDK_GUIDE_NAME"
|
||||||
WORD_GUIDE="$(find "$REPO_ROOT" "$REPO_ROOT/Docs" -maxdepth 1 -type f -name '*SDK*.docx' ! -name '~$*' 2>/dev/null | sort | sed -n '1p')"
|
|
||||||
WORD_GUIDE_INCLUDED=false
|
|
||||||
if [[ -n "$WORD_GUIDE" ]]; then
|
|
||||||
cp "$WORD_GUIDE" "$OUTPUT_DIR/$(basename "$WORD_GUIDE")"
|
|
||||||
WORD_GUIDE_INCLUDED=true
|
|
||||||
else
|
else
|
||||||
echo "Warning: SDK Word guide is missing. Continue packaging with Markdown documents in Docs/." >&2
|
echo "SIMCAE packaging guide is missing: $SDK_GUIDE_SOURCE" >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cp "$SCRIPT_DIR/package-sdk.sh" "$OUTPUT_DIR/scripts/package-sdk.sh"
|
cp "$SCRIPT_DIR/package-sdk.sh" "$OUTPUT_DIR/scripts/package-sdk.sh"
|
||||||
@@ -135,8 +131,8 @@ cat > "$OUTPUT_DIR/sdk_manifest.json" <<EOF
|
|||||||
"contains_demo_main_app": $([[ "$INCLUDE_DEMO_MAIN_APP" -eq 1 ]] && echo true || echo false),
|
"contains_demo_main_app": $([[ "$INCLUDE_DEMO_MAIN_APP" -eq 1 ]] && echo true || echo false),
|
||||||
"contains_qt_runtime": $([[ "$INCLUDE_QT_RUNTIME" -eq 1 ]] && echo true || echo false),
|
"contains_qt_runtime": $([[ "$INCLUDE_QT_RUNTIME" -eq 1 ]] && echo true || echo false),
|
||||||
"contains_final_config": false,
|
"contains_final_config": false,
|
||||||
"docs_entry": "Docs/01-客户端接入打包部署指南.md",
|
"docs_entry": "$SDK_GUIDE_NAME",
|
||||||
"word_guide_included": $WORD_GUIDE_INCLUDED,
|
"word_guide_included": false,
|
||||||
"integration_sources": [
|
"integration_sources": [
|
||||||
"ConfigHelper.h",
|
"ConfigHelper.h",
|
||||||
"ConfigHelper.cpp",
|
"ConfigHelper.cpp",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Hub 更新客户端打包成 SDK
|
# Updater 打包成 SDK
|
||||||
|
|
||||||
本文只说明如何从 `SIMCAE/update-client` 生成给 SIMCAE 开发者使用的 SDK 包。SIMCAE 如何拿这个 SDK 打客户安装器和交付包,见项目根目录的 [客户端部署.md](../../客户端部署.md)。
|
本文只说明如何从 `SIMCAE/update-client` 生成给 SIMCAE 打包流程使用的更新客户端 SDK。SIMCAE 如何拿这个 SDK 打客户安装器和交付包,见当前目录《SIMCAE打包上传.md》。
|
||||||
|
|
||||||
## 一、SDK 包含什么
|
## 一、SDK 包含什么
|
||||||
|
|
||||||
@@ -12,10 +12,12 @@ SDK 用来把 Hub 更新客户端接入 SIMCAE 安装包。
|
|||||||
| `Updater.exe` | 拉取 Manifest、下载发布包、校验 SHA-256、准备安装 |
|
| `Updater.exe` | 拉取 Manifest、下载发布包、校验 SHA-256、准备安装 |
|
||||||
| `Bootstrap.exe` | 替换运行中文件时接管安装 |
|
| `Bootstrap.exe` | 替换运行中文件时接管安装 |
|
||||||
| Qt 运行库 | 可选,给没有单独 Qt 运行环境的接入方使用 |
|
| Qt 运行库 | 可选,给没有单独 Qt 运行环境的接入方使用 |
|
||||||
| 文档 | 说明客户端目录结构、配置字段和接入方式 |
|
| `SIMCAE打包上传.md` | 给 SIMCAE 发布人员看的打包、交付包组装和上传说明 |
|
||||||
|
|
||||||
SDK 不包含最终客户配置文件,例如 `app_config.json`、`server_config.json`、`server_config.qrc`、`manifest_public_key.pem`。这些文件由服务端在上传客户软件包或 Qt IFW 交付包时生成或注入。
|
SDK 不包含最终客户配置文件,例如 `app_config.json`、`server_config.json`、`server_config.qrc`、`manifest_public_key.pem`。这些文件由服务端在上传客户软件包或 Qt IFW 交付包时生成或注入。
|
||||||
|
|
||||||
|
打包后的 SDK 根目录只放 `SIMCAE打包上传.md` 这一份使用说明。本文是维护者打 SDK 的说明,不随 SDK 一起交给接入方。
|
||||||
|
|
||||||
## 二、编译 Release
|
## 二、编译 Release
|
||||||
|
|
||||||
先进入 SIMCAE 仓库下的 `update-client` 目录。如果当前已经在 SIMCAE 仓库根目录:
|
先进入 SIMCAE 仓库下的 `update-client` 目录。如果当前已经在 SIMCAE 仓库根目录:
|
||||||
@@ -27,10 +29,12 @@ cd .\update-client
|
|||||||
然后执行:
|
然后执行:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
cmake --preset x64-release
|
cmake --preset x64-release -DSIMCAE_OPENSSL_ROOT="C:\Program Files\OpenSSL-Win64"
|
||||||
cmake --build --preset x64-release
|
cmake --build --preset x64-release
|
||||||
```
|
```
|
||||||
|
|
||||||
|
如果 OpenSSL 安装在其他目录,只改 `SIMCAE_OPENSSL_ROOT` 这一项。
|
||||||
|
|
||||||
编译完成后,Release 产物通常位于 `out/bin/Release`。
|
编译完成后,Release 产物通常位于 `out/bin/Release`。
|
||||||
|
|
||||||
检查核心程序:
|
检查核心程序:
|
||||||
@@ -50,8 +54,8 @@ Test-Path .\out\bin\Release\Bootstrap.exe
|
|||||||
```powershell
|
```powershell
|
||||||
.\scripts\package-sdk.ps1 `
|
.\scripts\package-sdk.ps1 `
|
||||||
-SourceDir .\out\bin\Release `
|
-SourceDir .\out\bin\Release `
|
||||||
-OutputDir .\dist\SimCAEHubUpdateClientSDK `
|
-OutputDir .\dist\UpdateClientSDK `
|
||||||
-ZipFile .\dist\SimCAEHubUpdateClientSDK.zip `
|
-ZipFile .\dist\UpdateClientSDK.zip `
|
||||||
-SdkVersion 0.1.0
|
-SdkVersion 0.1.0
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -59,8 +63,8 @@ Test-Path .\out\bin\Release\Bootstrap.exe
|
|||||||
|
|
||||||
| 输出 | 说明 |
|
| 输出 | 说明 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `dist\SimCAEHubUpdateClientSDK` | SDK 展开目录 |
|
| `dist\UpdateClientSDK` | 不带 Qt 运行库的 SDK 展开目录 |
|
||||||
| `dist\SimCAEHubUpdateClientSDK.zip` | 可交给 SIMCAE 开发者的 SDK 压缩包 |
|
| `dist\UpdateClientSDK.zip` | 不带 Qt 运行库的 SDK 压缩包 |
|
||||||
|
|
||||||
## 四、打包带 Qt 运行库的 SDK
|
## 四、打包带 Qt 运行库的 SDK
|
||||||
|
|
||||||
@@ -69,33 +73,36 @@ Test-Path .\out\bin\Release\Bootstrap.exe
|
|||||||
```powershell
|
```powershell
|
||||||
.\scripts\package-sdk.ps1 `
|
.\scripts\package-sdk.ps1 `
|
||||||
-SourceDir .\out\bin\Release `
|
-SourceDir .\out\bin\Release `
|
||||||
-OutputDir .\dist\SimCAEHubUpdateClientSDK-with-qt `
|
-OutputDir .\dist\UpdateClientSDK-With-QtDll `
|
||||||
-ZipFile .\dist\SimCAEHubUpdateClientSDK-with-qt.zip `
|
-ZipFile .\dist\UpdateClientSDK-With-QtDll.zip `
|
||||||
-SdkVersion 0.1.0 `
|
-SdkVersion 0.1.0 `
|
||||||
-IncludeQtRuntime
|
-IncludeQtRuntime
|
||||||
```
|
```
|
||||||
|
|
||||||
|
这里的 `With-QtDll` 表示包里带的是运行所需的 Qt DLL,不是完整 Qt SDK。
|
||||||
|
|
||||||
输出:
|
输出:
|
||||||
|
|
||||||
| 输出 | 说明 |
|
| 输出 | 说明 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `dist\SimCAEHubUpdateClientSDK-with-qt` | 带 Qt 运行库的 SDK 展开目录 |
|
| `dist\UpdateClientSDK-With-QtDll` | 带 Qt 运行库 DLL 的 SDK 展开目录 |
|
||||||
| `dist\SimCAEHubUpdateClientSDK-with-qt.zip` | 推荐交给 SIMCAE 开发者的 SDK 压缩包 |
|
| `dist\UpdateClientSDK-With-QtDll.zip` | 推荐交给 SIMCAE 开发者的 SDK 压缩包 |
|
||||||
|
|
||||||
## 五、打包后检查
|
## 五、打包后检查
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
Test-Path .\dist\SimCAEHubUpdateClientSDK-with-qt\bin\Launcher.exe
|
Test-Path .\dist\UpdateClientSDK-With-QtDll\bin\Launcher.exe
|
||||||
Test-Path .\dist\SimCAEHubUpdateClientSDK-with-qt\bin\Updater.exe
|
Test-Path .\dist\UpdateClientSDK-With-QtDll\bin\Updater.exe
|
||||||
Test-Path .\dist\SimCAEHubUpdateClientSDK-with-qt\bin\Bootstrap.exe
|
Test-Path .\dist\UpdateClientSDK-With-QtDll\bin\Bootstrap.exe
|
||||||
Test-Path .\dist\SimCAEHubUpdateClientSDK-with-qt.zip
|
Test-Path .\dist\UpdateClientSDK-With-QtDll\SIMCAE打包上传.md
|
||||||
|
Test-Path .\dist\UpdateClientSDK-With-QtDll.zip
|
||||||
```
|
```
|
||||||
|
|
||||||
预期都返回 `True`。
|
预期都返回 `True`。
|
||||||
|
|
||||||
## 六、不要提交的内容
|
## 六、不要提交的内容
|
||||||
|
|
||||||
`SIMCAE/update-client/.gitignore` 已忽略这些本地内容:
|
当前仓库的 `.gitignore` 已忽略这些本地内容:
|
||||||
|
|
||||||
- `thirdparty/`
|
- `thirdparty/`
|
||||||
- `out/`
|
- `out/`
|
||||||
Reference in New Issue
Block a user