ZTools打包与自动更新全链路:electron-builder跨平台构建与Rust updater二进制实战
【免费下载链接】ZToolsAn open-source implementation of uTools, a high-performance, scalable application launcher and plugin platform | Supports macOS and Windows, 一个高性能、可扩展的应用启动器和插件平台 uTools 的开源实现 | 支持 macOS 和 Windows项目地址: https://gitcode.com/gh_mirrors/ztool/ZTools
ZTools 是一款开源的应用启动器与插件平台(uTools 的开源实现,支持 macOS 和 Windows)。本文带你完整走一遍它的工程链路:从electron-builder跨平台打包、构建产物瘦身,到 Rust 编写的 updater 二进制与应用内自动更新,理解一个生产级桌面应用是如何"打完包、更得动"的。
为什么值得研究这条链路?
很多 Electron 项目"能跑",但发布环节经常踩坑:安装包臃肿、更新失败、双架构合并麻烦。ZTools 的做法有几个亮点:
- 单文件构建配置:所有平台差异收敛到一份 YAML;
- 签名前注入"完整安装标记":让更新器能识别旧版安装并引导迁移;
- Rust updater 二进制:macOS 双架构预编译,随包分发;
- 更新元数据脚本化:
latest.yml/latest-mac.yml自动生成并校验。
一键跨平台构建:electron-builder 脚本
ZTools 基于 Electron 41 + electron-vite + electron-builder 26。所有构建入口都收敛在 package.json 的scripts中:
| 脚本 | 作用 |
|---|---|
build:win | 构建 Windows NSIS 安装包 + zip |
build:mac | 构建 macOS DMG + zip(签名公证) |
build:mac:x64/build:mac:arm64 | 分别构建 Intel / Apple Silicon |
build:linux | 构建 AppImage 与 deb |
build:unpack | 仅解包不产安装包,适合快速验证 |
updater | 生成/合并更新元数据(node scripts/updater.mjs) |
每个脚本都用cross-env ZTOOLS_TARGET_PLATFORM=...指定目标平台,保证在任意 CI 机器上都能确定性地构建。
一份 YAML 管住三个平台:electron-builder.yml
electron-builder.yml 是整个打包链路的核心,关键配置一览:
全局瘦身
files中显式排除src、tests、docs、scripts、internal-plugins、锁文件与 tsconfig 等开发文件;- 排除
node_modules里的.d.ts、openai 的src、lmdb 与 uiohook-napi 的源码目录,避免"源码混入产物"; asarUnpack只保留运行时必须解包的resources/**和sharp、@img原生模块;npmRebuild: false跳过原生模块重编译,交给预编译产物,显著缩短构建时间。
Windows
- 目标为
nsis(x64)+zip; oneClick: false+allowToChangeInstallationDirectory: true:给用户选择安装目录的自由;createDesktopShortcut: always;卸载时保留用户数据(deleteAppDataOnUninstall: false)。
macOS
- 目标为
dmg+zip,开启notarize: true公证; LSUIElement: true:作为启动器常驻菜单栏,不显示 Dock 图标;- 声明相机/麦克风/文档/下载目录权限描述,避免运行时权限弹窗歧义。
其他
fileAssociations注册了.zpx(ZTools 插件包)关联,双击即可安装插件;afterPack: ./build/afterPack.js是产物"最后一步"的钩子,下面细讲。
afterPack 钩子:签名前写入更新兼容标记
build/afterPack.js 在 electron-builder 打完包、正式签名之前执行两件事:
- 写入完整安装标记
ztools-install-info.json(含appId: top.z-tools、Electron 版本、updater 类型electron-updater-mac/electron-updater-nsis)。应用更新时靠它判断当前安装是否为"标准完整安装",否则(如旧的绿色版)会引导用户迁移一次完整版本,避免签名与运行时状态不一致; - 按平台+架构清理无用原生资源:扫描
ia32、armv7l等不匹配的预编译模块并删除,防止安装包"背着一堆用不到的二进制"。
标记必须写进最终Contents/Resources且赶在签名前完成——这正是 afterPack 钩子存在的意义:在 electron-builder 的标准化流程中,插入一段项目自己的质量关卡。
Rust updater 二进制:macOS 更新的执行者
仓库根目录的 updater/ 目录存放了两份预编译的 Rust 更新器:
updater/mac-amd64/ztools-updater(约 2.8 MB,Intel)updater/mac-arm64/ztools-updater(约 2.7 MB,Apple Silicon)
用 Rust 而非 Node 脚本做更新器的好处很实际:单文件、零运行时依赖、启动快、崩溃面小。它由 CI 交叉编译后以二进制形式进入仓库,打包时按架构随包分发,应用内更新流程直接调用它完成下载校验与替换。
更新元数据:latest.yml 与 latest-mac.yml
应用内更新依赖"latest 文件"(版本号 + 下载地址 + SHA-512 校验)。scripts/updater.mjs 负责在 CI 中合并生成:
- Windows:读取构建产出的
latest.yml,注入changelog.md的发布说明后写出; - macOS 双架构:分别读取
MAC_X64_UPDATE_METADATA与MAC_ARM64_UPDATE_METADATA两份元数据,合并成一份latest-mac.yml(同时包含 x64 与 arm64 的 ZIP 地址),并通过validateReferencedAsset确认 YAML 引用的完整 ZIP 确实存在于构建产物中——元数据与实际产物不匹配时直接构建失败; - 最后把各平台下载链接追加到 changelog.md,一次发布,文档与更新源同步就绪。
开发模式下,dev-app-update.yml 指向项目的 Release 源,让未打包的pnpm dev也能走"检查更新"逻辑而不报错。
应用内自动更新:从心跳检查到静默替换
运行时更新链路分为三层,全部位于主进程:
调度层src/main/api/updater.ts
UpdaterAPI注册updater:check-update、updater:start-update、updater:cancel-update、updater:install-downloaded-update等 IPC 通道;- 更新检查由活动心跳统一调度(
handleHeartbeatUpdate),并尊重用户在设置里的"自动检查更新"开关; - 支持服务端下发的多下载渠道:应用内渠道走标准更新器,人工渠道则用系统浏览器打开(且强制校验 HTTPS);
- 发现新版本后弹出一个 500×450 的无边框置顶更新窗口(
updater.html),展示版本、发布说明与下载进度。
标准更新器封装src/main/api/electronUpdater.ts
ElectronUpdaterService把electron-updater的autoUpdater封装成清晰的状态机:idle → checking → available → downloading → downloaded → installing;- 关闭后台静默安装(
autoDownload = false),下载与重启时机全部交给更新窗口,用户可控、可取消(CancellationToken中断下载后回到 available 状态); - 优先差分下载,失败回退完整包;
- 安装时 Windows 走 NSIS
installDirectory,macOS 交给 Squirrel 替换应用包。
平台适配器src/main/api/platformUpdater/
macos.ts:初始化前先校验安装兼容性(src/main/api/macInstallCompatibility.ts)。旧版非签名安装不能直接进 Squirrel 流程,会弹出一次性迁移提示,引导用户装一次完整 DMG,数据与插件全保留;windows.ts:NSIS 安装目录保留、覆盖安装逻辑;disabled.ts:不支持的平台直接降级为手动下载引导。
这种"接口不变、按平台替换实现"的结构,让更新窗口的 UI 与交互代码完全不用关心平台差异。
测试如何兜底这条链路?
更新与构建相关的关键逻辑都有单测覆盖,位于 tests/main/ 目录,例如:
- electronUpdater.test.ts:状态机、差分下载、取消语义;
- serverUpdateCatalog.test.ts、updateSource.test.ts:服务端更新目录解析与下载渠道判定;
- updaterWindow.test.ts、macInstallCompatibility.test.ts、windowsInstallCompatibility.test.ts:更新窗口与安装兼容性迁移。
小结
ZTools 的发布与更新链路可以概括为四步:
- electron-builder.yml用一份配置管住 Win/mac/Linux 三平台产物与瘦身策略;
- afterPack 钩子在签名前写入安装标记、清理无关二进制;
- Rust updater 二进制(
updater/双架构预编译)+scripts/updater.mjs元数据合并,保证"更新源"与"执行者"都可靠; - 三层更新架构(调度 → 标准更新器 → 平台适配器)让应用内更新可取消、可迁移、跨平台行为一致。
如果你想在自己项目中复刻这套实践,建议从最小闭环开始:先跑通latest.yml+ electron-updater,再逐步加入 afterPack 标记、多架构元数据合并与安装兼容性迁移提示。相关源码可参考 docs/ 下的开发文档与上文列出的各模块文件。
【免费下载链接】ZToolsAn open-source implementation of uTools, a high-performance, scalable application launcher and plugin platform | Supports macOS and Windows, 一个高性能、可扩展的应用启动器和插件平台 uTools 的开源实现 | 支持 macOS 和 Windows项目地址: https://gitcode.com/gh_mirrors/ztool/ZTools
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考