17 KiB
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。
打包前确认:
- 已在 Windows 上用 Release 配置编译完成,输出目录里有
Launcher.exe、Updater.exe、Bootstrap.exe。 config/manifest_public_key.pem和服务端使用的私钥是一对。- SDK Word 接入说明已经放在
update-client根目录或update-client/Docs目录下,文件名包含SDK,例如SimCAE自动升级SDK接入说明_v0.1.docx。打包脚本会把它复制到 SDK 根目录,方便接入方一打开压缩包就能看到。 - 如果业务软件本身已经带 Qt DLL,通常不要把 SDK 的 Qt 运行库打进去,避免 Qt 版本混用。
在 Windows 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
生成结果:
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 打包方式:
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:
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 放进业务软件目录
假设业务软件目录是:
D:\SimCAE\
bin\
SimCAE.exe
Qt5Core.dll
...
Licenses\
installerResources\
推荐把 SDK 放到 bin 目录,和 SimCAE.exe 同级;后台发布新版本时仍选择整个 D:\SimCAE\ 作为发布根目录。
先解压 SDK:
Expand-Archive D:\交付\UpdateClientSDK.zip -DestinationPath D:\SimCAE_SDK -Force
再安装到业务软件的 bin 目录:
cd D:\SimCAE\bin
D:\SimCAE_SDK\scripts\install-sdk.ps1 `
-SdkRoot D:\SimCAE_SDK `
-ReleaseDir .
安装后目录应类似:
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:
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
最推荐的方式是在服务端管理后台生成客户端配置:
- 浏览器打开服务端管理后台,例如
http://服务器IP:8000/。 - 登录后台。
- 创建或选择应用,例如
app_id=simcae。 - 创建 License。
- 在“客户端配置生成”区域选择应用、渠道、License 和主程序名。
- 点击生成配置。
- 复制生成的 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。
典型配置:
{
"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"
}
五、你:业务主程序需要配合什么
当前安全模式下,业务主程序需要配合两件事:
- 接收
--ticket-file=<path>参数,验证并消费一次性启动票据。 - 如果收到
--health-file=<path>参数,启动成功后向该路径写入ok\n,让 Updater 确认新版本可用。
接入位置:
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 来校验,就会出现:
ticket signature, identity, time or nonce invalid
或者细化后的:
ticket device_id mismatch
业务主程序应像 MainApp/main.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 完全来自同一套运行配置。
六、你:准备服务端数据
首次联调前,服务端至少要准备这些内容:
- 创建应用,例如
simcae。 - 创建渠道,例如
stable。 - 创建 License。
- 发布一个初始版本,例如
1.0.0。 - 生成客户端配置,并写入
bin\config\app_config.json。客户端下次启动时会自动同步到注册表。
为什么必须先发布初始版本:Launcher 启动业务主程序前会做 Manifest 完整性校验。这个 Manifest 是服务端发布版本时生成并签名的清单,用来证明当前本地文件属于一个可信版本。如果没有发布过 current_version 对应版本,客户端会提示签名 Manifest 缓存缺失。
后台发布版本时,选择整个安装根目录,例如 D:\SimCAE\,不要只选择 D:\SimCAE\bin。这样服务端会把 bin/SimCAE.exe、Licenses/、installerResources/ 等完整结构写进 Manifest。
七、你:运行和联调
基础联调步骤:
- 确认服务端正在运行。
- 确认
bin\config\app_config.json中api_base_url、client_token、license_key、current_version正确。 - 双击
bin\Launcher.exe。 - 首次启动时如果
license_key为空,按弹窗输入后台创建的 License;SDK 会把它保存到注册表。 - 成功进入业务主程序后,回到后台查看设备、升级日志、下载日志。
- 在后台发布更高版本,例如从
1.0.0发布到1.0.1。 - 再次启动
Launcher.exe,验证升级、健康确认和回滚逻辑。
联调目录建议:
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 中执行:
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 缓存。
- 是否存在重复主程序。
生成结果:
dist/
UpdateClient/
UpdateClient.zip
Linux 最终客户端包生成方式:
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 那样自动提权修改安装目录。正式部署前建议二选一:
- 把软件安装到当前用户有写权限的目录,例如用户 home 下的应用目录。
- 由安装器创建专用目录和权限,让运行用户对软件目录有写入权限。
九、常见错误
- 直接启动业务主程序提示 ticket 错误:应从
Launcher.exe启动。 - 首次启动保存配置/状态文件失败:如果目录不可写,SDK 会弹出管理员权限确认框;用户取消或当前账号没有管理员权限时仍会失败。
- 首次启动设备登记失败:检查
api_base_url、client_token、license_key、服务端 License 状态。 - 提示 License 错误或过期:在后台确认 License 是否存在、是否被禁用或删除、是否超过最大设备数。
- 策略或 Manifest 验签失败:检查
config/manifest_public_key.pem是否和服务端私钥匹配。 - 提示 signed manifest cache missing:先在后台发布一次
current_version对应版本,并让客户端拿到该版本 Manifest。 - 升级后回滚:检查业务程序是否在
health_check_timeout_ms内写入健康标记。 - 发布失败提示主程序不在根目录:服务端
.env中RELEASE_MAIN_EXECUTABLE要和平台匹配。Windows 通常是bin/SimCAE.exe;Linux 通常是bin/SimCAE。 - 启动时提示
无法定位程序输入点 ... Qt5*.dll:通常是 Qt DLL 被不同版本覆盖或混用。恢复业务软件原始 Qt DLL,并重新打包 SDK;SimCAE 场景下不要使用-IncludeQtRuntime。