Tauri 开发
概述
Tauri 是一个构建跨平台桌面应用的框架,使用 Web 前端技术(HTML / CSS / JavaScript)编写 UI 层,通过各操作系统原生 WebView 渲染,并以 Rust 编写高性能、安全的后端逻辑。Tauri 由 Tauri 社区维护,采用 MIT 或 Apache 2.0 许可协议。
与 Electron 的对比
| 维度 | Tauri | Electron |
|---|---|---|
| UI 渲染 | 系统原生 WebView(Edge WebView2 / WKWebView / WebKitGTK) | 捆绑 Chromium |
| 后端语言 | Rust | Node.js(Chromium 进程) |
| 打包体积 | 约 3–10 MB(不含 WebView) | 约 120–300 MB |
| 内存占用 | 约 30–80 MB(基础应用) | 约 120–300 MB(基础应用) |
| 启动速度 | 快(百毫秒级) | 较慢(秒级) |
| 安全模型 | 能力系统 + CSP + API 白名单 | 无强制安全模型 |
| 跨平台 | Windows / macOS / Linux / iOS / Android(实验性) | Windows / macOS / Linux |
| 更新机制 | Tauri Updater(内置) | electron-updater 或自定义 |
架构
Tauri 应用的核心架构分为三层:
- Web 层 — 前端应用,使用任意 Web 框架(React / Vue / Svelte 等),运行在系统原生 WebView 中。
- Bridge 层 — Tauri Core,一个 Rust 编写的中间件,负责进程间通信(IPC)、窗口管理、事件系统以及能力校验。
- 系统层 — 操作系统原生 API 调用,通过 Rust 的 Command 系统和插件机制暴露给前端。
┌─────────────────────────────────────┐
│ Web Frontend │
│ (React / Vue / Svelte / ... ) │
│ WebView 环境 │
├─────────────────────────────────────┤
│ Tauri Core (Rust) │
│ IPC · 窗口管理 · 事件 · 能力 │
├─────────────────────────────────────┤
│ OS API · 文件系统 · 系统托盘 │
│ Plugin 生态系统 │
└─────────────────────────────────────┘Rust 核心
Tauri 使用 Rust 作为后端语言,编译为原生二进制文件。Rust 在内存安全和零成本抽象方面的特性使得 Tauri 能够在提供高性能的同时避免常见的内存安全问题(如空指针、缓冲区溢出)。
Rust 后端通过 tauri::command 宏暴露函数给前端调用,并通过 invoke 机制实现前后端通信。
WebView
Tauri 不捆绑浏览器引擎,而是使用各操作系统自带的 WebView:
- Windows — Edge WebView2(基于 Chromium,Windows 10 / 11 内置或自动安装)
- macOS — WKWebView(基于 Safari)
- Linux — WebKitGTK
采用系统 WebView 的好处在于:应用体积大大减小,内存使用更低,且安全性更好(WebView 与系统安全策略保持一致)。
包体积
得益于不捆绑 Chromium,Tauri 应用的安装包体积通常在 3–10 MB 之间,而同等功能的 Electron 应用通常为 120–300 MB。这对用户的下载带宽、磁盘占用以及分发成本都有显著的改善。
启动速度
由于只需加载轻量级 WebView 而非启动完整的 Chromium 进程,Tauri 应用的冷启动时间通常在数百毫秒级别,远快于 Electron 的秒级启动。
Rust 后端
Command 系统
Tauri 通过 #[tauri::command] 属性宏将 Rust 函数暴露给前端调用。前端通过 invoke 函数调用这些命令。
#[tauri::command]
fn greet(name: &str) -> String {
format!("你好, {}! 来自 Tauri 后端的问候。", name)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("启动应用失败");
}前端调用方式:
import { invoke } from '@tauri-apps/api/tauri';
const result = await invoke('greet', { name: 'Tauri' });Command 系统支持异步函数、返回 Result 处理错误、使用状态管理(tauri::State)共享数据等高级用法。
Tray Plugin(系统托盘)
系统托盘是桌面应用常见功能,Tauri 通过 tauri-plugin-tray 提供支持。该插件允许应用在系统托盘中显示图标,创建右键菜单,以及处理托盘事件。
基本配置:
use tauri_plugin_tray::{TrayIconBuilder, MenuBuilder};
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_tray::init())
.setup(|app| {
let tray = TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.menu(
MenuBuilder::new()
.item("显示窗口")
.item("退出")
.build()?,
)
.build()?;
// 处理托盘点击事件
tray.on_menu_event(|app, event| {
match event.id.as_str() {
"显示窗口" => { /* 显示主窗口 */ }
"退出" => app.exit(0),
_ => {}
}
});
Ok(())
})
.run(tauri::generate_context!())
.expect("启动失败");
}Shell 命令
Tauri 提供 tauri-plugin-shell 来执行系统命令。出于安全考虑,所有 shell 命令必须在 tauri.conf.json 中显式声明白名单。
// Rust 侧 - 使用 tauri-plugin-shell
use tauri_plugin_shell::ShellExt;
#[tauri::command]
async fn run_cmd(app: tauri::AppHandle) -> Result<String, String> {
let output = app.shell()
.command("ping")
.args(["-c", "3", "localhost"])
.output()
.await
.map_err(|e| e.to_string())?;
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}配置项(tauri.conf.json):
{
"plugins": {
"shell": {
"all": false,
"scope": [
{
"name": "ping",
"cmd": "ping",
"args": true
}
]
}
}
}系统信息
利用 Rust 后端的系统调用能力,可以获取当前系统的硬件和软件信息:
- 操作系统类型与版本
- CPU 架构与核心数
- 内存总量与使用量
- 磁盘信息
- 主机名与网络信息
可通过 sysinfo 等 Rust crate 或在 Command 中直接调用标准库的系统相关函数来实现。
文件系统
Tauri 提供了 tauri::api::path 模块和 @tauri-apps/api/fs 前端 API 来进行文件系统操作。文件系统的访问受到能力系统的严格控制。
文件系统
Tauri 的文件系统 API 提供对应用沙箱内目录的读写能力,以及访问系统标准目录的能力。
核心 API
以下为常用文件系统操作:
读取目录
use std::fs;
use tauri::api::path;
#[tauri::command]
fn read_notes_dir(app: tauri::AppHandle) -> Result<Vec<String>, String> {
let app_dir = path::app_data_dir(&app.config())
.ok_or("无法获取应用数据目录")?;
let notes_dir = app_dir.join("notes");
if !notes_dir.exists() {
fs::create_dir_all(¬es_dir).map_err(|e| e.to_string())?;
return Ok(vec![]);
}
let entries = fs::read_dir(¬es_dir).map_err(|e| e.to_string())?;
let mut files = vec![];
for entry in entries {
let entry = entry.map_err(|e| e.to_string())?;
if let Some(name) = entry.file_name().to_str() {
files.push(name.to_string());
}
}
Ok(files)
}写入文件
#[tauri::command]
fn save_note(app: tauri::AppHandle, filename: String, content: String) -> Result<(), String> {
let app_dir = tauri::api::path::app_data_dir(&app.config())
.ok_or("无法获取应用数据目录")?;
let notes_dir = app_dir.join("notes");
fs::create_dir_all(¬es_dir).map_err(|e| e.to_string())?;
let file_path = notes_dir.join(&filename);
fs::write(&file_path, &content).map_err(|e| e.to_string())?;
Ok(())
}删除文件
#[tauri::command]
fn delete_note(app: tauri::AppHandle, filename: String) -> Result<(), String> {
let app_dir = tauri::api::path::app_data_dir(&app.config())
.ok_or("无法获取应用数据目录")?;
let file_path = app_dir.join("notes").join(&filename);
if file_path.exists() {
fs::remove_file(&file_path).map_err(|e| e.to_string())?;
}
Ok(())
}appDataDir
app_data_dir 是应用存储用户数据的标准目录,在 Windows 上对应 %APPDATA%/<你的应用名>,在 macOS 上对应 ~/Library/Application Support/<你的应用名>,在 Linux 上对应 ~/.local/share/<你的应用名>。Tauri 通过 tauri::api::path::app_data_dir 函数获取该路径。
其他可用路径包括:
app_config_dir— 配置文件目录app_cache_dir— 缓存目录app_log_dir— 日志目录desktop_dir— 桌面目录document_dir— 文档目录download_dir— 下载目录home_dir— 用户主目录
资源路径
Tauri 允许将文件作为资源打包到应用中。在 tauri.conf.json 中配置:
{
"tauri": {
"bundle": {
"resources": [
"resources/**/*"
]
}
}
}在 Rust 后端通过 app.path().resource_dir() 获取打包资源的路径,然后在 Command 中提供给前端使用。资源目录在打包后会被复制到应用安装目录下。
前端也可以通过 @tauri-apps/api/path 模块中的 resourceDir 函数获取资源目录路径。
系统托盘
系统托盘是桌面应用与操作系统交互的重要组件。Tauri 通过插件系统提供完善的系统托盘支持。
tray-plugin 安装
在 Cargo.toml 中添加依赖:
[dependencies]
tauri-plugin-tray = "2"在前端项目中安装对应的 npm 包:
npm install @tauri-apps/plugin-tray右键菜单
系统托盘右键菜单通过 MenuBuilder 或 Menu API 创建:
use tauri_plugin_tray::TrayIconBuilder;
// 创建带菜单的托盘图标
let tray = TrayIconBuilder::new()
.tooltip("Tauri 应用")
.icon(app.default_window_icon().unwrap().clone())
.menu(
MenuBuilder::new()
.text("打开主窗口", "open")
.separator()
.text("关于", "about")
.separator()
.text("退出", "quit")
.build()?,
)
.build_on(app)?;图标
托盘图标支持以下格式:
- Windows:
.ico格式 - macOS:
.png格式(建议 22x22 或 44x44) - Linux:
.png格式
图标文件应当放置在应用资源目录中,并在 tauri.conf.json 中配置。
事件处理
系统托盘支持以下事件类型:
on_menu_event— 菜单项点击事件on_tray_icon_event— 托盘图标交互事件(左键点击、双击等)on_tray_menu_event— 整个托盘菜单的事件处理
tray.on_tray_icon_event(|tray, event| {
match event {
TrayIconEvent::Click { .. } => {
// 左键点击:显示主窗口
let window = tray.app_handle().get_window("main").unwrap();
let _ = window.show();
let _ = window.set_focus();
}
TrayIconEvent::DoubleClick { .. } => {
// 双击:切换窗口显隐
}
_ => {}
}
});通知
Tauri 支持通过 tauri-plugin-notification 或系统原生的通知机制发送桌面通知:
use tauri_plugin_notification::NotificationExt;
#[tauri::command]
async fn send_notification(app: tauri::AppHandle, title: String, body: String) -> Result<(), String> {
app.notification()
.builder()
.title(&title)
.body(&body)
.show()
.map_err(|e| e.to_string())?;
Ok(())
}前端调用:
import { sendNotification, isPermissionGranted, requestPermission } from '@tauri-apps/plugin-notification';
if (!(await isPermissionGranted())) {
await requestPermission();
}
sendNotification({ title: '新消息', body: '您有一条来自 Tauri 的通知' });Tauri vs Electron 全面对比
下表从多个维度对 Tauri 和 Electron 进行全面对比:
| 维度 | Tauri | Electron |
|---|---|---|
| 首次发布 | 2021 年 | 2013 年 |
| UI 渲染引擎 | 系统原生 WebView | 捆绑 Chromium |
| 后端语言 | Rust | Node.js(主进程) |
| 前端框架 | 任意(React / Vue / Svelte / 原生 HTML) | 任意 |
| 安装包体积 | 3–10 MB | 120–300 MB |
| 运行时内存 | 30–80 MB | 120–300 MB |
| 启动时间 | 200–500 ms | 1–3 秒 |
| 安全性 | 能力系统 + CSP + API 白名单 | 需手动加固 |
| 自动更新 | Tauri Updater(内置) | 需第三方库 |
| 原生 API | Rust 绑定 + 插件生态 | Node.js 原生模块 + 插件 |
| Windows 支持 | Windows 7+(需安装 WebView2) | Windows 7+ |
| macOS 支持 | macOS 10.13+ | macOS 10.10+ |
| Linux 支持 | 主流发行版 | 主流发行版 |
| 移动端支持 | iOS / Android(实验性) | 不直接支持 |
| 开发者工具 | WebView DevTools | Chromium DevTools |
| 社区规模 | 快速增长中 | 成熟庞大 |
| 学习曲线 | 需要 Rust 基础知识 | 前端开发者即可上手 |
| 自动构建/CI | tauri-action (GitHub Actions) | electron-builder |
| 适合场景 | 对体积/性能/安全敏感的应用 | 快速原型、复杂的 Node.js 依赖项目 |
选型建议
选择 Tauri,如果:
- 应用体积和内存占用是关键考量
- 启动速度要求高
- 对安全性有严格要求
- 团队有 Rust 能力或愿意学习 Rust
- 目标是构建一个低资源消耗的桌面工具
选择 Electron,如果:
- 需要快速原型验证
- 项目重度依赖 Node.js 生态(如大量 npm 原生模块)
- 团队以纯前端开发者为主,无 Rust 经验
- 需要支持 Windows 7 且无法分发 WebView2 安装包
- 应用需要使用 Chromium 的高级渲染特性(如 WebRTC、Canvas 高级功能)
安全模型
Tauri 将安全性作为核心设计原则,通过多层安全机制保护应用和用户数据。
CSP(内容安全策略)
CSP 是浏览器层面的安全机制,用于防止 XSS 攻击和数据注入。Tauri 允许在 tauri.conf.json 中配置 CSP:
{
"tauri": {
"security": {
"csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
}
}
}严格的 CSP 配置可以防止恶意脚本的执行,即使攻击者注入了 HTML 内容。
能力系统
Tauri v2 引入了能力系统(Capability System),这是 Tauri 安全模型的核心。能力系统要求应用显式声明可使用的 API 权限。
能力在 capabilities/ 目录下的 JSON 文件中定义:
{
"identifier": "default",
"description": "默认能力配置",
"windows": ["main"],
"permissions": [
"core:default",
"shell:allow-open",
"fs:allow-read-text-file",
"fs:allow-write-text-file",
"notification:default",
"dialog:default"
]
}能力系统的工作原理:
- 每个 API 调用都会经过能力校验
- 只有显式声明的权限才会被授予
- 不同窗口可以有不同的能力配置
- 能力配置由应用开发者控制,无法被运行时修改
API 白名单
除了能力系统,Tauri 还支持在 tauri.conf.json 中设置 API 白名单。例如 shell 插件的命令白名单:
{
"plugins": {
"shell": {
"all": false,
"scope": [
{
"name": "allowed-command",
"cmd": "git",
"args": [
{ "validator": "\\S+" }
]
}
]
}
}
}这种方式确保只有经过审核的命令和参数可以被执行,有效防止命令注入攻击。
协议隔离
Tauri 使用自定义协议(tauri://)来处理前端资源和 API 调用,与标准的 file:// 或 https:// 协议隔离。这带来了以下安全优势:
- 前端页面无法直接访问文件系统中的任意文件
- IPC 调用经过协议层校验
- 自定义协议不受 Web 标准协议的跨域策略限制
跨平台打包与发布
Tauri 使用 tauri build 命令将应用打包为各平台的原生安装程序。
打包命令
# 安装 Tauri CLI
cargo install tauri-cli
# 构建与打包
cargo tauri build平台特定配置
在 tauri.conf.json 的 bundle 字段中配置打包参数:
{
"tauri": {
"bundle": {
"active": true,
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"identifier": "com.example.app",
"targets": "all"
}
}
}Windows 打包
- 生成 MSI 安装程序(基于 WiX Toolset)
- 支持 NSIS 安装器(需额外配置)
- 可配置数字签名(代码签名证书)
- 生成
.msi或.exe安装包
macOS 打包
- 生成
.dmg磁盘映像 - 支持
.app程序包 - 支持代码签名(Apple Developer 证书)
- 支持公证(Notarization)
Linux 打包
- 支持
.deb(Debian / Ubuntu) - 支持
.AppImage(通用包格式) - 支持
.rpm(Fedora / RHEL) - 支持 Snap 包
自动更新
Tauri 内置了自动更新机制(Tauri Updater):
- 在
tauri.conf.json中配置更新服务器地址:
{
"plugins": {
"updater": {
"endpoints": ["https://releases.example.com/update/{{target}}/{{current_version}}"],
"pubkey": "your-public-key"
}
}
}- 在 Rust 后端注册更新插件:
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_updater::Builder::new().build())
.run(tauri::generate_context!())
.expect("启动失败");
}- 前端检查更新:
import { checkUpdate, installUpdate } from '@tauri-apps/plugin-updater';
const { shouldUpdate, manifest } = await checkUpdate();
if (shouldUpdate) {
await installUpdate();
}更新机制支持全量更新和增量更新,并且更新文件经过数字签名验证,确保分发安全。
CI/CD 集成
Tauri 提供了 tauri-action 用于 GitHub Actions 自动化构建:
- name: Build Tauri app
uses: tauri-apps/tauri-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tagName: v__VERSION__
releaseName: 'v__VERSION__'
releaseBody: '查看发布说明'
releaseDraft: true
prerelease: false