Tauri 2 桌面应用¶
为什么要学¶
Tauri 用 Rust + Web 技术构建跨平台桌面应用,是 Electron 的现代替代:
- 极小体积:应用体积 600KB 起(Electron 动辄 100MB+)
- 低内存占用:Rust 后端,内存使用仅 Electron 的 1/10
- 安全第一:Rust 内存安全 + 细粒度权限系统
- 跨平台:Windows/macOS/Linux,Tauri 2 还支持 iOS/Android
- 前端自由:任何前端框架(React/Vue/Svelte/Solid)
- 系统集成:原生菜单、通知、托盘、文件系统等
如果你想构建轻量、安全、高性能的桌面应用,Tauri 是 2024+ 的最佳选择。
核心概念¶
白话解释¶
- 前端:你的 Web 页面(HTML/CSS/JS),显示界面
- Core(Rust后端):用 Rust 写的系统级功能,处理文件/网络/系统调用
- IPC:前端和 Rust 后端之间的通信桥梁
- Webview:操作系统自带的浏览器引擎(不捆绑 Chromium)
核心概念对照表¶
| Tauri | Electron | 说明 |
|---|---|---|
| Webview | Chromium | 渲染前端(使用系统WebView) |
| Rust Core | Node.js Main | 后端进程 |
| Commands | IPC handlers | 前后端通信 |
| Plugins | Node modules | 功能扩展 |
| Permissions | (无限制) | 安全权限控制 |
| ~600KB | ~100MB+ | 应用体积 |
| ~20MB RAM | ~200MB RAM | 内存占用 |
安装配置¶
前置要求¶
# Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 系统依赖
# macOS: Xcode Command Line Tools
xcode-select --install
# Ubuntu
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget \
file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
# Windows: 安装Visual Studio Build Tools + WebView2
创建项目¶
# 使用create-tauri-app
npm create tauri-app@latest
# 选项:
# Project name: my-app
# Frontend: React/Vue/Svelte/Solid/Vanilla
# TypeScript: Yes
cd my-app
npm install
npm run tauri dev
项目结构¶
my-app/
├── src/ # 前端代码
│ ├── App.tsx
│ └── main.tsx
├── src-tauri/ # Rust后端
│ ├── src/
│ │ ├── main.rs
│ │ └── lib.rs
│ ├── Cargo.toml
│ ├── tauri.conf.json
│ └── capabilities/
│ └── default.json
├── package.json
└── vite.config.ts
快速上手¶
前后端通信(Commands)¶
Rust 端定义命令:
// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! From Rust!", name)
}
#[tauri::command]
async fn read_file(path: String) -> Result<String, String> {
std::fs::read_to_string(&path)
.map_err(|e| e.to_string())
}
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet, read_file])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
前端调用:
import { invoke } from '@tauri-apps/api/core';
// 调用Rust命令
const greeting = await invoke<string>('greet', { name: '张三' });
console.log(greeting); // "Hello, 张三! From Rust!"
const content = await invoke<string>('read_file', { path: '/tmp/test.txt' });
权限配置¶
// src-tauri/capabilities/default.json
{
"identifier": "default",
"windows": ["main"],
"permissions": [
"core:default",
"fs:allow-read-text-file",
"fs:allow-write-text-file",
"dialog:allow-open",
"dialog:allow-save",
"notification:default"
]
}
文件对话框¶
import { open, save } from '@tauri-apps/plugin-dialog';
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
// 打开文件
async function openFile() {
const path = await open({
filters: [{ name: 'Text', extensions: ['txt', 'md'] }]
});
if (path) {
const content = await readTextFile(path);
return content;
}
}
// 保存文件
async function saveFile(content: string) {
const path = await save({
filters: [{ name: 'Text', extensions: ['txt'] }]
});
if (path) {
await writeTextFile(path, content);
}
}
进阶用法¶
1. 系统托盘¶
use tauri::{
menu::{Menu, MenuItem},
tray::TrayIconBuilder,
};
pub fn run() {
tauri::Builder::default()
.setup(|app| {
let quit = MenuItem::with_id(app, "quit", "退出", true, None::<&str>)?;
let show = MenuItem::with_id(app, "show", "显示窗口", true, None::<&str>)?;
let menu = Menu::with_items(app, &[&show, &quit])?;
TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.menu(&menu)
.on_menu_event(|app, event| match event.id.as_ref() {
"quit" => app.exit(0),
"show" => {
if let Some(window) = app.get_webview_window("main") {
window.show().unwrap();
}
}
_ => {}
})
.build(app)?;
Ok(())
})
.run(tauri::generate_context!())
.unwrap();
}
2. 插件系统¶
# 安装官方插件
npm install @tauri-apps/plugin-fs
npm install @tauri-apps/plugin-dialog
npm install @tauri-apps/plugin-notification
npm install @tauri-apps/plugin-shell
npm install @tauri-apps/plugin-store # 持久化KV存储
// Cargo.toml中添加
[dependencies]
tauri-plugin-fs = "2"
tauri-plugin-dialog = "2"
tauri-plugin-store = "2"
// lib.rs中注册
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_store::Builder::new().build())
.run(tauri::generate_context!())
.unwrap();
}
3. 事件系统¶
// Rust发送事件到前端
#[tauri::command]
async fn start_download(app: tauri::AppHandle) {
for i in 0..100 {
app.emit("download-progress", i).unwrap();
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
}
}
// 前端监听事件
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen<number>('download-progress', (event) => {
console.log(`Progress: ${event.payload}%`);
});
// 取消监听
unlisten();
4. 多窗口¶
import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
const newWindow = new WebviewWindow('settings', {
url: '/settings',
title: '设置',
width: 600,
height: 400,
resizable: false,
});
newWindow.once('tauri://created', () => {
console.log('窗口创建成功');
});
5. 构建发布¶
# 构建
npm run tauri build
# 输出:
# Windows: .msi / .exe
# macOS: .dmg / .app
# Linux: .deb / .AppImage
# 交叉编译(需要CI)
# 参考: github.com/tauri-apps/tauri-action
常见问题¶
Q1: 不同平台 WebView 差异?¶
| 平台 | WebView引擎 | 注意事项 |
|---|---|---|
| Windows | WebView2 (Chromium) | 需Win10+ |
| macOS | WKWebView (WebKit) | Safari行为 |
| Linux | WebKitGTK | 版本可能旧 |
Q2: 不会 Rust 怎么办?¶
- 简单应用可以用 JS 插件完成大部分功能
- Rust 端只需要写简单的 Command
- 社区插件覆盖了常见需求
- Tauri 的 Rust 代码通常很简单
Q3: 和 Electron 如何选择?¶
| 方面 | Tauri | Electron |
|---|---|---|
| 体积 | 极小(~1-5MB) | 大(~100MB+) |
| 性能 | 高 | 中 |
| 生态 | 增长中 | 非常成熟 |
| WebView一致性 | 平台有差异 | 完全一致(Chromium) |
| 学习成本 | 需学少量Rust | 纯JS |
参考资源¶
- Tauri 官网 - 官方网站
- Tauri 文档 - v2 文档
- Tauri GitHub - 源代码
- Tauri 插件 - 官方插件
- Awesome Tauri - 社区资源