Files
update-client/Docs/01-客户端接入打包部署指南.md

19 KiB
Raw Permalink Blame History

UpdateClientSDK 客户端接入、打包和部署指南

本文按“维护者打包 SDK -> 你接入业务软件 -> 联调测试 -> 生成最终客户端包”的顺序说明。你拿到这份文档后,按章节一步一步做即可。

先看这里:你要做哪件事

你的目标 直接看哪一节
重新生成给别人用的 SDK 包 二、维护者:生成 SDK 包
把 SDK 放到 SimCAE 或其他业务软件目录 三、你:把 SDK 放进业务软件目录
从后台生成 app_config.json 和 qrc 服务端配置 四、你:生成并填写客户端配置
给业务主程序接入启动保护代码 五、你:业务主程序接入要求
验证升级、回滚、健康检查 六、你:联调测试
生成最终交付给用户的客户端包 七、维护者:生成最终客户端包

一、这个 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/server_config.json:编译期服务端地址配置源文件,通过 config/server_config.qrc 编进 Launcher / Updater / MainApp,不写入 app_config.json 或注册表。
  • config/manifest_public_key.pem:Manifest 签名公钥,用来验证服务端发布包没有被篡改。

二、维护者:生成 SDK 包

这一节是 SDK 维护者操作。接入方通常只需要拿到 UpdateClientSDK.zip

打包前确认:

  1. 已在 Windows 上用 Release 配置编译完成,输出目录里有 Launcher.exeUpdater.exeBootstrap.exe
  2. config/manifest_public_key.pem 和服务端使用的私钥是一对。
  3. update-client/Docs 里的 Markdown 文档会随 SDK 一起打包,是默认接入说明来源。
  4. Word 接入说明是可选增强。如果本地有文件名包含 SDK.docx,打包脚本会额外复制到 SDK 根目录;如果没有,也不会影响 SDK 打包。
  5. 如果业务软件本身已经带 Qt DLL,通常不要把 SDK 的 Qt 运行库打进去,避免 Qt 版本混用。

在 Windows PowerShell 中执行:

cd C:\Users\admin\Desktop\update-client

.\scripts\package-sdk.ps1 `
  -SourceDir .\out\bin\Release `
  -OutputDir .\dist\UpdateClientSDK `
  -ZipFile .\dist\UpdateClientSDK.zip `
  -SdkVersion 0.1.0

生成结果:

dist/
  UpdateClientSDK/
    sdk_manifest.json
    Docs/
      00-先读我-客户端文档入口.txt
      01-客户端接入打包部署指南.md
      02-编译环境和第三方依赖说明.md
    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
    SimCAE自动升级SDK接入说明_v0.1.docx   # 可选:只有本地存在 Word 说明时才会出现
  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/
    sdk_manifest.json
    Docs/
      00-先读我-客户端文档入口.txt
      01-客户端接入打包部署指南.md
      02-编译环境和第三方依赖说明.md
    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
    SimCAE自动升级SDK接入说明_v0.1.docx   # 可选:只有本地存在 Word 说明时才会出现
  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*.dllplatforms/imageformats/ 等目录。不要把另一套 Qt DLL 覆盖到 SimCAE\bin,否则可能出现“无法定位程序输入点”一类错误。

四、你:生成并填写客户端配置

最推荐的方式是在服务端管理后台生成客户端配置:

  1. 浏览器打开服务端管理后台,例如 http://服务器IP:8000/
  2. 登录后台。
  3. 创建或选择应用,例如 app_id=simcae
  4. 创建 License。
  5. 在“客户端配置生成”区域选择应用、渠道、License 和主程序名。
  6. 点击生成配置。
  7. 复制“客户端 app_config.json”,覆盖 D:\SimCAE\bin\config\app_config.json
  8. 复制“qrc 服务端配置 server_config.json”,覆盖 update-client\config\server_config.json,然后重新编译 Launcher / Updater / Bootstrap。这个文件会被 config/server_config.qrc 编进程序,不会放进用户机器的 app_config.json 或注册表。

配置同步规则:

  • app_config.json 是部署配置源文件,适合交付、复制、人工修改。
  • api_base_url 不再属于 app_config.json 字段。它只存在于 config/server_config.json,并通过 qrc 编进程序。
  • 交付给你的 SDK 运行包不会包含 server_config.jsonserver_config.qrc。它们是编译材料,不是运行配置;修改 SDK 包里的文件不会改变已经编译好的 Launcher.exe
  • 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 会同时删除当前用户数据目录里的 client_identity.datversion_policy.datlocal_state.json,避免继续使用旧 License、旧设备身份、旧版本策略或旧防回滚状态;这些运行态文件不再默认写入安装目录。
  • 正常启动成功后,不要删除 client_identity.datversion_policy.datlocal_state.json。它们分别用于本地设备身份、离线策略和防回滚/防时间倒退,删除后会影响离线启动或导致重新授权。
  • 注册表按安装目录隔离;同一台电脑上多个安装目录不会互相覆盖配置。
  • 注册表位置为 HKEY_CURRENT_USER\Software\Marsco\UpdateClientSDK\installations\<安装目录SHA256>\config

关键字段说明:

  • app_id:服务端应用 ID,要和管理后台里的应用一致。
  • app_name:应用显示名称。
  • channel:发布渠道,例如 stablebetadev
  • current_version:客户端当前初始版本,必须和后台已发布的版本一致。
  • client_protocol:客户端协议号,当前建议为 3
  • launch_token:本机启动票据 HMAC 密钥。服务端生成配置时会填默认值;正式部署建议按项目统一修改。
  • license_key:管理后台创建 License 后生成的授权码。为空时首次启动 Launcher.exe 会弹窗让用户输入并保存到注册表;如果授权错误或过期,也会提示重新输入。
  • 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_executableupdater_executablebootstrap_executable:通常不用改。
  • platformarch:当前为 windowsx64

典型配置:

{
  "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",
  "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"
}

对应的 config/server_config.json 示例:

{
  "api_base_url": "http://192.168.229.128:8000"
}

五、你:业务主程序需要配合什么

当前安全模式下,业务主程序需要配合两件事:

  1. 接收 --ticket-file=<path> 参数,验证并消费一次性启动票据。
  2. 如果收到 --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_iddevice_idcurrent_versionlaunch_tokenLauncher.exe 完全来自同一套运行配置。

六、你:准备服务端数据

首次联调前,服务端至少要准备这些内容:

  1. 创建应用,例如 simcae
  2. 创建渠道,例如 stable
  3. 创建 License。
  4. 发布一个初始版本,例如 1.0.0
  5. 生成客户端配置,并写入 bin\config\app_config.json。客户端下次启动时会自动同步到注册表。
  6. 生成 qrc 服务端配置,并写入源码目录 config\server_config.json 后重新编译 SDK 程序。

为什么必须先发布初始版本:Launcher 启动业务主程序前会做 Manifest 完整性校验。这个 Manifest 是服务端发布版本时生成并签名的清单,用来证明当前本地文件属于一个可信版本。如果没有发布过 current_version 对应版本,客户端会提示签名 Manifest 缓存缺失。

后台发布版本时,选择整个安装根目录,例如 D:\SimCAE\,不要只选择 D:\SimCAE\bin。这样服务端会把 bin/SimCAE.exeLicenses/installerResources/ 等完整结构写进 Manifest。

七、你:运行和联调

基础联调步骤:

  1. 确认服务端正在运行。
  2. 确认 bin\config\app_config.jsonclient_tokenlicense_keycurrent_version 正确,并确认 Launcher.exe 已用正确的 config/server_config.json 重新编译。
  3. 双击 bin\Launcher.exe
  4. 首次启动时如果 license_key 为空,按弹窗输入后台创建的 License;SDK 会把它保存到注册表。
  5. 成功进入业务主程序后,回到后台查看设备、升级日志、下载日志。
  6. 在后台发布更高版本,例如从 1.0.0 发布到 1.0.1
  7. 再次启动 Launcher.exe,验证升级、健康确认和回滚逻辑。

联调目录建议:

D:\SimCAE_Release\
C:\Users\<你的用户名>\Desktop\SimCAE_Release\

如果安装在 C:\Program Files\...D:\... 或其他普通用户不一定可写的目录,SDK 的普通配置值会写入当前用户注册表,不需要修改 app_config.jsonclient_identity.datlocal_state.jsonversion_policy.dat、更新缓存和 Manifest 缓存也会写入当前用户数据目录,不再默认写到安装目录。

Windows 用户数据目录类似:%LOCALAPPDATA%\Marsco\UpdateClientSDK\installations\<安装目录SHA256>\。因此日常启动、首次授权、保存设备身份、保存策略、防回滚状态和下载缓存不应再触发管理员权限确认框。只有真正要替换安装目录里的 EXE/DLL 等程序文件时,才需要保证安装目录可写,或让安装器/Updater 具备相应权限。

八、维护者:生成某个产品的最终客户端包

SDK 是给接入方开发使用的。最终给用户安装或分发时,可以从已经联调过的 Release 目录生成最终客户端包。

在 Windows PowerShell 中执行:

cd C:\Users\admin\Desktop\update-client

.\scripts\package-client.ps1 `
  -SourceDir .\out\bin\Release `
  -ConfigFile .\config\app_config.json `
  -OutputDir .\dist\UpdateClient `
  -ZipFile .\dist\UpdateClient.zip

package-client.ps1 会检查:

  • 配置文件必填字段是否完整。
  • 主程序、Launcher、Updater、Bootstrap 是否存在。
  • 是否混入 Debug DLL、PDB、ILK。
  • 当前版本是否已有签名 Manifest 缓存。脚本会优先从当前用户数据目录读取: %LOCALAPPDATA%\Marsco\UpdateClientSDK\installations\<安装目录SHA256>\update\manifest_cache。 同时兼容旧版 Release 目录里的 update\manifest_cache
  • 是否存在重复主程序。

生成结果:

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 缓存。脚本会优先从当前用户数据目录读取: $XDG_DATA_HOME/Marsco/UpdateClientSDK/installations/<安装目录SHA256>/update/manifest_cache 未设置 XDG_DATA_HOME 时通常是 ~/.local/share/Marsco/UpdateClientSDK/installations/<安装目录SHA256>/update/manifest_cache。 同时兼容旧版 Release 目录里的 update/manifest_cache
  • 是否存在重复主程序。

Linux 下如果程序安装在 /opt/usr/local 等普通用户不可写目录,升级器无法像 Windows UAC 那样自动提权修改安装目录。正式部署前建议二选一:

  1. 把软件安装到当前用户有写权限的目录,例如用户 home 下的应用目录。
  2. 由安装器创建专用目录和权限,让运行用户对软件目录有写入权限。

九、常见错误

  1. 直接启动业务主程序提示 ticket 错误:应从 Launcher.exe 启动。
  2. 首次启动保存配置/状态文件失败:如果目录不可写,SDK 会弹出管理员权限确认框;用户取消或当前账号没有管理员权限时仍会失败。
  3. 首次启动设备登记失败:检查编译进 qrc 的 config/server_config.jsonclient_tokenlicense_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. 发布失败提示主程序不在根目录:服务端 .envRELEASE_MAIN_EXECUTABLE 要和平台匹配。Windows 通常是 bin/SimCAE.exeLinux 通常是 bin/SimCAE
  9. 启动时提示 无法定位程序输入点 ... Qt5*.dll:通常是 Qt DLL 被不同版本覆盖或混用。恢复业务软件原始 Qt DLL,并重新打包 SDK;SimCAE 场景下不要使用 -IncludeQtRuntime