5月28日 02:09

Tauri 支持哪些自动更新方式?如何实现?

Tauri 是基于 Rust 和 Web 技术构建跨平台桌面应用的框架,自动更新能力是生产级应用的刚需。Tauri 通过 tauri-plugin-updater 插件提供官方更新方案,同时支持自定义更新服务器。本文从实际工程出发,讲清楚每种方式的核心配置和踩坑点。

Tauri 自动更新有哪些方式?

Tauri 的自动更新本质上只有一条主线:通过插件检测远端版本、下载签名包、验证后安装重启。区别在于更新清单托管在哪里:

  • 方式一:官方 tauri-plugin-updater + 静态 JSON 端点 — 最主流,适合绝大多数项目
  • 方式二:官方插件 + CrabNebula Cloud 托管 — 免搭建服务器,适合小团队
  • 方式三:自定义更新服务端 — 适合私有部署、灰度发布等企业场景

三种方式共用同一个插件核心,差异仅在更新清单的来源和签名流程。下面逐个展开。

方式一:tauri-plugin-updater + 静态 JSON 端点

这是官方推荐的标准方案,更新清单是一个静态 JSON 文件,可以托管在 GitHub Pages、S3、CDN 或任何能返回 JSON 的 HTTP 服务上。

安装依赖

bash
# 前端 pnpm add @tauri-apps/plugin-updater @tauri-apps/plugin-dialog @tauri-apps/plugin-process # Rust 端 cd src-tauri && cargo add tauri-plugin-updater --target 'cfg(desktop)' cargo add tauri-plugin-dialog --target 'cfg(desktop)' cargo add tauri-plugin-process --target 'cfg(desktop)'

三个插件缺一不可:updater 负责检测和下载,dialog 提供用户确认弹窗,process 负责更新后重启应用。

配置 tauri.conf.json

json
{ "plugins": { "updater": { "pubkey": "YOUR_PUBLIC_KEY_HERE", "endpoints": [ "https://your-cdn.com/updates/latest.json" ] } } }

pubkey 用于验证更新包签名,防止中间人篡改。endpoints 是更新清单地址,支持配置多个做冗余。

Rust 端注册插件

rust
// src-tauri/src/lib.rs #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .setup(|app| { #[cfg(desktop)] app.handle().plugin(tauri_plugin_updater::Builder::new().build())?; Ok(()) }) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_process::init()) .run(tauri::generate_context!()) .expect("error while running tauri application"); }

注意:updater 必须在 setup 闭包中注册,dialogprocess.plugin() 注册即可。

前端检查并安装更新

typescript
import { check } from "@tauri-apps/plugin-updater"; import { ask, message } from "@tauri-apps/plugin-dialog"; import { relaunch } from "@tauri-apps/plugin-process"; async function checkForUpdate() { const update = await check(); if (!update) { return; // 已是最新版本 } const yes = await ask( `发现新版本 ${update.version},是否立即更新?\n\n更新说明:${update.body || "无"}`, { title: "应用更新", kind: "info", okLabel: "更新", cancelLabel: "稍后" } ); if (!yes) return; await update.downloadAndInstall((event) => { switch (event.event) { case "Started": console.log(`下载中,文件大小:${event.data.contentLength} 字节`); break; case "Progress": console.log(`已下载:${event.data.chunkLength} 字节`); break; case "Finished": console.log("下载完成,准备安装"); break; } }); await message("更新完成,应用将重启", { title: "更新成功", kind: "info" }); await relaunch(); }

生成签名密钥对

更新包必须签名,构建前需要生成密钥对:

bash
# 生成密钥对(只需执行一次) pnpm tauri signer generate -w ~/.tauri/myapp.key

执行后会输出公钥(填入 tauri.conf.jsonpubkey),私钥保存在指定路径。构建时通过环境变量传入:

bash
export TAURI_PRIVATE_KEY=$(cat ~/.tauri/myapp.key) export TAURI_KEY_PASSWORD=你的密码 pnpm tauri build

构建产物中会自动包含签名文件(.sig),更新清单中的 signature 字段就来自这里。

更新清单 JSON 格式

json
{ "version": "1.2.0", "notes": "修复了登录超时问题,优化了启动速度", "pub_date": "2025-06-15T10:00:00Z", "platforms": { "windows-x86_64": { "signature": "dW50cnVzdGVkIGNvbW1lbnQ6...", "url": "https://your-cdn.com/app_1.2.0_x64.nsis.zip" }, "darwin-x86_64": { "signature": "dW50cnVzdGVkIGNvbW1lbnQ6...", "url": "https://your-cdn.com/app_1.2.0_x64.app.tar.gz" }, "darwin-aarch64": { "signature": "dW50cnVzdGVkIGNvbW1lbnQ6...", "url": "https://your-cdn.com/app_1.2.0_aarch64.app.tar.gz" }, "linux-x86_64": { "signature": "dW50cnVzdGVkIGNvbW1lbnQ6...", "url": "https://your-cdn.com/app_1.2.0_amd64.AppImage.tar.gz" } } }

每次发版时,将构建产物上传到 CDN,同时更新这个 JSON 文件即可。signature 来自构建产物同目录的 .sig 文件。

方式二:CrabNebula Cloud 托管

CrabNebula 是 Tauri 背后公司的云服务,提供开箱即用的更新托管,无需自建 CDN 或手动维护 JSON 清单。

配置方式

json
{ "plugins": { "updater": { "endpoints": [ "https://cdn.crabnebula.app/updates/your-app-identifier" ], "pubkey": "YOUR_PUBLIC_KEY_HERE" } } }

核心代码和方式一完全一致,唯一区别是 endpoints 指向 CrabNebula 的 CDN。构建完成后通过 CrabNebula CLI 推送更新:

bash
cn upload --appid your-app-identifier ./src-tauri/target/release/bundle

CrabNebula 会自动生成各平台的更新清单,省去手动维护 JSON 的麻烦。适合不想折腾 CDN 和 CI 流水线的小团队。

方式三:自定义更新服务端

企业场景可能需要灰度发布、强制更新、版本回退等策略,此时需要自定义服务端。服务端只需提供一个符合格式约定的 API:

服务端接口规范

shell
GET /api/updates/check?platform={platform}&current_version={version}

返回格式与静态 JSON 相同,但服务端可以根据请求参数实现更复杂的逻辑:

  • 灰度发布:按用户 ID 或地区分批推送
  • 强制更新:返回 mandatory: true 字段,前端跳过用户确认
  • 版本回退:将某个版本的 URL 指向上一个稳定版

前端代码只需将 endpoints 改为自定义 API 地址,其余逻辑不变。需要注意的是,自定义服务端同样必须返回正确的 signature,签名验证不能跳过。

常见问题

更新签名验证失败怎么办?

检查以下几点:公钥与私钥是否匹配、构建时是否正确设置了 TAURI_PRIVATE_KEY 环境变量、.sig 文件是否与安装包对应。常见原因是密钥对重新生成后没有更新 tauri.conf.json 中的 pubkey

Windows 更新时应用闪退?

Windows 平台上,Tauri 在安装 NSIS 包前会自动退出应用,这是正常行为。确保更新逻辑中没有在 downloadAndInstall 之后执行 UI 操作,重启由 relaunch() 处理。

macOS 上更新后应用被 Gatekeeper 拦截?

需要给 .app 包签名并公证(notarization)。未公证的应用更新后会被 macOS 安全机制拦截,用户需要手动在系统设置中放行。生产环境必须配置 Apple Developer 证书签名。

能否不签名直接更新?

不能。tauri-plugin-updater 强制要求签名验证,这是安全设计,不可关闭。如果不需要更新功能,直接不配置 updater 插件即可。

面试追问方向

  • 更新包的签名机制为什么不可跳过? — 防止中间人注入恶意代码,Rust 端用 Ed25519 验证,公钥编译时嵌入二进制,无法运行时篡改。
  • 如何实现灰度发布? — 服务端根据请求参数(用户 ID、地区、渠道)返回不同版本清单,前端无感知。
  • Tauri 更新和 Electron 自动更新的核心区别? — Tauri 强制签名验证、用系统 WebView 不捆绑 Chromium、更新包体积小两个数量级。
标签:Tauri