第 43 章 自动更新(tauri-plugin-updater + 签名)
本章目标
- 配置更新清单
latest.json。 - 生成更新签名(minisign / 内置
tauri signer)。 - 前端 UI:检查、下载、重启。
- 差分更新与渠道(stable/beta)。
一、安装插件
pnpm add @tauri-apps/plugin-updater
# Cargo.toml
tauri-plugin-updater = "2"
// lib.rs
.plugin(tauri_plugin_updater::Builder::new().build())
二、生成签名密钥对
pnpm tauri signer generate -w ~/.tauri/cloudtone.key
产出:
cloudtone.key(私钥,保密)。cloudtone.key.pub(公钥,放 tauri.conf.json)。
"plugins": {
"updater": {
"active": true,
"endpoints": [
"https://releases.cloudtone.app/{{target}}/{{current_version}}/latest.json"
],
"dialog": false,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6..."
}
}
{{target}} 示例:darwin-aarch64、windows-x86_64-msvc、linux-x86_64。
三、构建时签名
在 CI 上:
export TAURI_SIGNING_PRIVATE_KEY="$(cat $SECRET_KEY_FILE)"
export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="$PASS"
pnpm tauri build
构建完成后目录里会多出 .sig 文件。latest.json 示例:
{
"version": "1.2.3",
"pub_date": "2026-04-20T09:00:00Z",
"notes": "修复崩溃;新增均衡器;性能优化。",
"platforms": {
"darwin-aarch64": {
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6...",
"url": "https://releases.cloudtone.app/darwin-aarch64/1.2.3/CloudTone.app.tar.gz"
},
"windows-x86_64-msvc": {
"signature": "...",
"url": "https://releases.cloudtone.app/windows-x86_64-msvc/1.2.3/CloudTone.msi.zip"
}
}
}
四、前端代码
// src/features/updater/useUpdater.ts
import { check } from "@tauri-apps/plugin-updater";
import { relaunch } from "@tauri-apps/plugin-process";
import { useState } from "react";
export function useUpdater() {
const [state, setState] = useState<{ available?: boolean; version?: string; progress?: number; err?: string }>({});
async function run() {
try {
const update = await check();
if (!update) { setState({ available: false }); return; }
setState({ available: true, version: update.version });
await update.downloadAndInstall((event) => {
if (event.event === "Progress") {
setState(s => ({ ...s, progress: event.data.chunkLength }));
}
});
await relaunch();
} catch (e: any) { setState({ err: e.message }); }
}
return { ...state, run };
}
UI:
export function UpdateNotice() {
const { available, version, progress, err, run } = useUpdater();
if (!available) return null;
return (
<div className="fixed bottom-4 right-4 bg-surface-2 p-4 rounded-xl shadow-xl w-72">
<div className="font-semibold">发现新版本 v{version}</div>
<button onClick={run} className="mt-2 px-3 py-1 bg-brand-500 rounded">立即更新</button>
{progress !== undefined && <div className="mt-2 text-xs">下载中…</div>}
{err && <div className="mt-2 text-xs text-red-400">{err}</div>}
</div>
);
}
五、静默与计划
- 启动 30s 后检查:避免抢占用户首屏。
- 4 小时轮询:用
setInterval。 - 失败降噪:3 次失败后停一天。
useEffect(() => {
const t1 = setTimeout(() => check(), 30_000);
const t2 = setInterval(() => check(), 4 * 60 * 60 * 1000);
return () => { clearTimeout(t1); clearInterval(t2); };
}, []);
六、多渠道
endpoints 支持多个,按渠道切换:
"endpoints": [
"https://releases.cloudtone.app/{{channel}}/{{target}}/latest.json"
]
channel 可以从设置读,启动时拼入 URL(需要自己拦截 endpoint)。简单做法:两份 latest.json (/stable/... vs /beta/...),用户切渠道时改配置文件。
七、差分更新
Tauri 默认下载整包。对大应用(100MB+),可以:
- 服务端提供 bsdiff 补丁。
- 客户端先下 patch,用
bsdiff::patchapply。
这是工程优化项,初版可以不做。
八、回滚与紧急停更
- 线上出问题,把
latest.json改回旧版本即可(clients 检查会发现"已是最新")。 - 紧急:用 feature flag 远程配置关闭某功能,而不是靠更新。
九、macOS 公证 & Windows 签名
自动更新要求安装包本身通过 OS 的签名校验:
- macOS:Apple Developer ID + notarytool 公证(第 46 章细讲)。
- Windows:用代码签名证书(EV 为佳)签 .msi / .exe。
没签名的更新在 Gatekeeper / SmartScreen 上会被拦。
本章小结
- Tauri updater + 签名 = 低成本实现安全更新。
- UI 要克制,不打断用户。
- 基础架构之上还有渠道、差分、回滚策略。
动手时刻
- 生成密钥对,发布 v0.1.0。
- 改版本号到 0.1.1,生成新包,验证客户端自动弹提示。
下一章:性能优化。