☰
下载管理器如何一次点击升级 6 个平台:Rayburst 发布与自动更新机制完整指南
2026/11/4 15:36:56 网站建设 项目流程

下载管理器如何一次点击升级 6 个平台:Rayburst 发布与自动更新机制完整指南

【免费下载链接】rayburstRedefining the open-source download manager项目地址: https://gitcode.com/gh_mirrors/mo/rayburst

下次当你在 Rayburst 里盯着一条任务的速度曲线时顺手点下"检查更新",有一件事可能不太符合直觉:更新包正在下载,而下载引擎本身还在照常跑,你的任务一秒都没停。这个基于 Tauri 2 + Rust + Vue 3 重写的下载管理器,把"更新"拆成了检查、下载、安装三个各自独立的动作,直到最后一步才短暂停掉内置的 Aria2 Next 引擎。

更反直觉的是它的更新入口是个"永久地址"——客户端从未请求过任何带版本号的 URL,它永远去同一个叫updater的固定 Release 里取latest.json或beta.json,取到哪个渠道、装哪个版本,全靠标签名和一份可随时覆盖的清单决定。本文不沿着"打标签→跑 CI→收安装包"的时间线讲,而是反过来:先给你一张全链路速览图,再挑三个最值得抄的设计决策拆开看。

先给地图:一条更新链路涉及的六个角色

角色住在哪一句话职责
版本号src-tauri/Cargo.toml唯一事实来源,package.json与Cargo.lock由脚本同步,不手改
发布开关scripts/release.sh本地先跑完整质量门禁,全绿才提交、打vX.Y.Z标签并推送
构建矩阵.github/workflows/release.yml在release: published事件后并行构建 6 平台,注入签名私钥生成.sig
渠道清单.github/scripts/refresh-updater-json.sh按标签名产出latest.json或beta.json,覆盖上传到固定updaterRelease
更新运行时src-tauri/src/commands/updater.rs渠道选择、可取消下载、两阶段安装、签名校验的 Rust 侧核心
前端状态机src/composables/useUpdateFlow.ts更新对话框的按钮文案、可关闭性、进度换算,全部纯函数

记住这张表后,下面三个深挖都可以对号入座。

深挖一:把更新入口钉死在一个"永久地址"上

它解决什么。桌面应用的自动更新有个天然矛盾:用户所在渠道(stable 还是 beta)会变化,发布频率也会变化,但客户端代码里的更新端点最好永远不用变。端点一变,老版本就得重新分发,渠道切换就变成了一次"版本升级"。

怎么落地。CI 侧由refresh-updater-json.sh负责:先校验标签名形如v主.次.补丁,再按规则分流——标签含-beta/-alpha/-rc就生成beta.json,否则生成latest.json。它会逐个确认全部 10 个平台产物(macOSapp.tar.gz×2、Windows NSIS ×2、Linux AppImage / deb / rpm ×6)和对应.sig签名都存在,缺一个就中止,然后用jq组装出包含版本号、发布说明、发布时间和 10 组"下载 URL + 签名"的 JSON,最后上传到一个名为updater的固定 Release 上(不存在就先建),并用--clobber覆盖旧文件。客户端侧,updater.rs 里的UPDATER_BASE_URL指向这个永久地址,plugins.updater.pubkey内置在 tauri.conf.json 中,更新包必须通过 Ed25519 签名校验,校验器发现公钥没配置时直接拒绝工作。

为什么这么做、有何取舍。这份清单是"指向最新版的指针",不是版本历史:回退版本不是回退 JSON,而是重新发布旧标签。配套的纪律是"标签 = 不可变指针"——构建失败时,修完代码要删掉远端标签、删掉 Release、再走一遍发布,而不是往旧标签上补东西。另一个值得注意的细节:release.yml的merge-updater-json任务在SIGNPATH_ENABLED开启时会主动让位,把发布渠道 JSON 的权力移交给 Windows 签名工作流,保证"先装 Authenticode 签名、再签发 updater 签名、最后才动渠道清单"这个顺序不被并发破坏。

深挖二:用 5 种 Runner 装下 6 个构建目标

它解决什么。macOS 双架构、Windows 双架构、Linux 双架构,共 6 个目标,其中 Windows ARM64 在 x86 Runner 上没有原生工具链,Linux ARM64 则根本没有现成云 Runner 可选。

怎么落地。release.yml 用matrix.include声明 6 行任务,但实际只占用 5 种 Runner:macos-26和macos-26-intel各建一个 macOS 架构;Windows x64 与 ARM64 两个任务挤在同一台windows-2025-vs2026上,ARM64 那个靠rustup target add交叉编译——注释里写明理由是"NSIS 与架构无关";Linux 则是ubuntu-22.04加ubuntu-22.04-arm。矩阵设了fail-fast: false,一个架构挂了不连累其余五路。构建时注入TAURI_SIGNING_PRIVATE_KEY,每个产物都产出一个.sig。

矩阵里还藏着几个很"工程"的细节:预发布版的 RPM 会被单独打包一次,因为 RPM 的release编号规则与 App 版本号冲突,rpm-version.sh先算出版本、tauri bundle单独再打一遍并用tauri signer sign --app-version补签名;Windows 产物会被grep检查 import 表里不得出现vcruntime140之类的动态链接符号——安装包会临时目录里直接运行 exe,用户机器不一定装了 VC++ 运行库;Linux 的 AppImage 通过LINUXDEPLOY_EXCLUDED_LIBRARIES排除libwayland-*,注释说明自带一份会在新版 Mesa 上弄坏 EGL、窗口打不开(#714)。

取舍在哪。交叉编译省掉一台 Windows ARM Runner,代价是构建顺序里多一步rustup target add;update-homebrew任务则只在 stable 正式版且HOMEBREW_ENABLED开启时运行,用brew bump-cask-pr --write-only自动更新 cask,把"发布即同步包管理器"做成无感动作,代价是它必须排在全矩阵构建之后。

深挖三:更新流程如何给"正在跑的任务"让路

它解决什么。对一个下载管理器来说,最糟糕的更新体验是"点了更新,下载全停"。Windows 上还有个硬约束:NSIS 无法覆盖正在运行的 exe,所以安装前必须停引擎——问题是停引擎的时机应尽量晚。

怎么落地。整个流程被拆进四个 Tauri 命令:check_for_update(channel, proxy)只做元数据探测,给 15 秒超时、走UpdaterBuilder的按请求代理而非改环境变量;download_update(version)下载字节流,期间 Aria2 Next 引擎不中断,用户任务无感,进度通过update-progress事件实时推给前端,并且用tokio::select!把下载 Future 和一个Notify取消信号做竞速,cancel_update一触发就退出;apply_update才进入两阶段——先通过EngineSupervisor停掉引擎(注释写明是为了让 NSIS 能覆盖、并防止会话文件损坏),再执行安装,如果安装失败,还会调用ensure_running把引擎救活,避免"更新失败导致应用残废"。

护栏同样具体:download_update要求传入的版本号必须与最近一次检查结果一致,不一致就提示"重新检查";每次检查会递增一个 generation 计数,结果返回前发现已被更新的检查取代,直接返回冲突错误。签名层面,build_updater发现公钥缺失会直接报错,字节流验签失败则归入"下载或签名校验失败"。

为什么这么做。下载与安装解耦后,"更新"从一次阻塞操作变成了三段可随时介入的状态:检查、下载(可取消)、安装(需确认)。前端在 useUpdateFlow.ts 里把这映射成一个七相位状态机(checking / up-to-date / available / downloading / ready / installing / error),每个相位对应明确的按钮文案、按钮类型和"对话框能否关闭"规则——downloading与installing期间禁止关闭,error相位给出重试。渠道策略也在这里体现:用户偏好存为updateChannel(stable或beta,且 beta 构建默认落在 beta 渠道),选stable时只查latest.json,选beta时会并发查两条渠道,再用 SemVer 的cmp_precedence挑真正更新的那个——单元测试里就断言了"stable3.8.8对阵 beta3.8.8-beta.4时选 stable",避免 beta 用户被同版本号的预发布版反复"升级"。

给想读源码的人:20 分钟阅读路径

想动手把这套机制过一遍,按这个顺序走(约 20~30 分钟):

git clone https://gitcode.com/gh_mirrors/mo/rayburst
  1. scripts/release.sh(5 分钟)——发布的起点。重点看它跑完哪一串门禁(ESLint、format:check、vue-tsc、Vitest、cargo fmt --check、clippy -D warnings、cargo test)后才允许提交、打注解标签并推送,以及末尾按标签名判定 STABLE / PRE-RELEASE 的几行;
  2. .github/workflows/release.yml(5 分钟)——看matrix.include的 6 行、Windows ARM64 交叉编译那一步、签名私钥的注入位置,以及merge-updater-json任务上那句"SignPath 启用时让位"的条件;
  3. .github/scripts/refresh-updater-json.sh(5 分钟)——渠道 JSON 的完整生产链:标签校验 → 逐资产/签名核对 →jq组装 → 覆盖上传固定 Release;
  4. src-tauri/src/commands/updater.rs(8 分钟)——核心中的核心:candidate_channels_for_policy的双渠道选择、select_latest_candidate的 SemVer 比较、tokio::select!竞速取消、apply_update的两阶段与引擎恢复,文件末尾的单元测试基本把渠道选择逻辑全测了一遍,值得连读;
  5. src/composables/useUpdateFlow.ts(3 分钟)——看后端命令如何被前端状态机消费,纯函数化让每个相位的行为都能单测。

顺带一提:scripts/bump-version.sh 虽然只有几行,但"版本号只从Cargo.toml出发、原子同步到package.json和Cargo.lock"这条纪律,是整条链路能自动化的地基。

三条可以搬走的经验

  • 发布的入口是脚本和标签,不是人手。质量门禁在打标签前本地完整跑一遍,CI 只做最终形态;版本号单一来源,杜绝"前端显示 1.4.0、后端还是 1.3.9"这类漂移。
  • 渠道 = 固定地址 + 可覆盖清单。客户端端点永不变,渠道由标签名决定,清单每次发布覆盖——更新入口因此可以比应用本身活得更久。
  • 更新流程要为业务让路。下载、安装解耦,引擎只在安装瞬间停摆,且失败有恢复路径。对一个以"持续下载"为存在意义的应用,这条比任何签名细节都优先。

回到开头那个场景:你在 Rayburst 里点下的那次"检查更新",背后其实是固定地址上的渠道 JSON、六个并行的签名构建、以及一段敢于在任务运行时下载、只在最后一刻才停引擎的三段式流程。小体积、快更新、强校验,这套 release + updater 组合拳对任何 Tauri 桌面项目都是可以直接对号入座的答案。

【免费下载链接】rayburstRedefining the open-source download manager项目地址: https://gitcode.com/gh_mirrors/mo/rayburst

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询