Tauri 是一个开源框架,使用 Rust 后端和任意 Web 前端构建轻量、安全的跨平台桌面应用。与 Electron 不同,Tauri 不捆绑 Chromium 或 Node.js,因此二进制文件极小(通常低于 5 MB)、内存占用更低、安全模型更强。Tauri 2.0 将支持扩展到 iOS 和 Android,使其成为追求原生性能与 Web 开发灵活性的开发者的理想选择。
Tauri 是一个由 Rust 驱动的跨平台桌面应用框架,支持 React、Vue、Svelte、SolidJS 等 Web 前端。二进制文件低于 5 MB,内存占用比 Electron 少 50-80%,具有细粒度权限安全模型,Tauri 2.0 支持 iOS/Android 移动端。Rust 后端处理系统 API,前端在操作系统原生 webview 中渲染。
- Tauri 应用远小于 Electron,因为它使用操作系统原生 webview 而非捆绑 Chromium,二进制文件通常低于 5 MB。
- Rust 后端提供内存安全、高性能和直接系统 API 访问,无垃圾回收开销。
- Tauri 2.0 引入了 iOS 和 Android 移动端支持,单一代码库可同时覆盖桌面和移动平台。
- 细粒度权限系统控制前端可访问的系统 API,使 Tauri 应用默认比 Electron 更安全。
- Tauri 支持任意 Web 前端框架,包括 React、Vue、Svelte、SolidJS 和纯 HTML/CSS/JS。
- 插件生态提供本地存储、SQL 数据库、HTTP 请求、文件系统访问、Shell 命令和自动更新等即用模块。
什么是 Tauri,它是如何工作的?
Tauri 是一个构建桌面应用的工具包,用户界面使用 Web 技术(HTML、CSS、JavaScript)构建,后端逻辑运行在 Rust 中。Tauri 使用操作系统自带的 webview:Windows 上的 WebView2、macOS 上的 WebKit、Linux 上的 WebKitGTK。
这种架构意味着 Tauri 应用继承宿主操作系统的渲染引擎,而 Rust 核心处理文件访问、窗口管理和进程间通信等系统级操作。结果是应用体积小一个数量级,内存消耗远低于 Electron 应用。
// Tauri Architecture Overview
//
// +---------------------------+
// | Web Frontend |
// | (React/Vue/Svelte/etc) |
// | HTML + CSS + JS |
// +---------------------------+
// | IPC (invoke / events)
// +---------------------------+
// | Tauri Core (Rust) |
// | Commands, Plugins, State |
// | Window Mgmt, FS, Shell |
// +---------------------------+
// | OS APIs
// +---------------------------+
// | OS Native Webview |
// | WebView2 / WebKit / |
// | WebKitGTK |
// +---------------------------+Tauri vs Electron:详细对比
开发者最常问的问题是 Tauri 和 Electron 有什么区别。以下是关键差异的对比:
| 特性 | Tauri | Electron |
|---|---|---|
| 后端语言 | Rust | Node.js (JavaScript) |
| 渲染引擎 | 操作系统原生 webview | 捆绑 Chromium |
| 二进制大小(Hello World) | ~3-5 MB | ~150-200 MB |
| 内存占用 | ~30-80 MB | ~150-300 MB |
| 安全模型 | 细粒度权限 | 完整 Node.js 访问 |
| 移动端支持 | iOS 和 Android(v2) | 不支持 |
| 冷启动时间 | ~0.5-1 秒 | ~2-5 秒 |
| 自动更新 | 内置插件 | electron-updater |
Tauri 2.0 新特性
Tauri 2.0 是一个重大版本,围绕插件化架构重构了框架并添加了移动端支持。核心已重写为更模块化的设计,许多 Tauri 1.x 的内置功能现在是需要主动引入的官方插件。
主要变化包括替代 v1 allowlist 的新权限系统、一等 iOS 和 Android 支持、Swift 和 Kotlin 绑定、多 webview API 以及显著改进的 IPC 性能。
使用 create-tauri-app 搭建项目
创建新 Tauri 项目最快的方式是使用官方脚手架工具,开箱支持多种前端框架和包管理器。
# Create a new Tauri project with the interactive CLI
npm create tauri-app@latest
# Or specify options directly
npm create tauri-app@latest my-app -- \
--template react-ts
# Available templates:
# vanilla, vanilla-ts, react, react-ts,
# vue, vue-ts, svelte, svelte-ts,
# solid, solid-ts, angular, preact, preact-ts
# Project structure after scaffolding:
# my-app/
# src/ <- frontend code (React/Vue/etc)
# src-tauri/
# src/
# main.rs <- Rust entry point
# lib.rs <- command definitions
# Cargo.toml <- Rust dependencies
# tauri.conf.json <- Tauri configuration
# capabilities/ <- permissions config
# package.json# Development commands
cd my-app
npm install
# Start dev server with hot-reload
npm run tauri dev
# Build for production
npm run tauri build
# Add mobile targets
npm run tauri android init
npm run tauri ios init
# Run on mobile
npm run tauri android dev
npm run tauri ios devRust 命令与 Invoke 系统
Tauri 命令是前端通过 IPC 桥调用的 Rust 函数。使用 #[tauri::command] 属性在 Rust 中定义,通过 invoke 从 JavaScript 调用。命令可以接受参数、返回值并访问应用状态。
命令在 Rust 端运行,拥有对文件系统、网络和任何 Rust crate 的完整访问。IPC 层使用 serde 自动序列化和反序列化参数和返回值。
// src-tauri/src/lib.rs
use tauri::State;
use std::sync::Mutex;
// Simple command with arguments and return value
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! From Rust.", name)
}
// Async command for I/O operations
#[tauri::command]
async fn read_file(path: String) -> Result<String, String> {
std::fs::read_to_string(&path)
.map_err(|e| e.to_string())
}
// Command with application state
struct AppState {
count: Mutex<i32>,
}
#[tauri::command]
fn increment(state: State<AppState>) -> i32 {
let mut count = state.count.lock().unwrap();
*count += 1;
*count
}
// Register commands in the app builder
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.manage(AppState { count: Mutex::new(0) })
.invoke_handler(tauri::generate_handler![
greet, read_file, increment
])
.run(tauri::generate_context!())
.expect("error while running application");
}// Frontend: calling Rust commands from JavaScript
import { invoke } from "@tauri-apps/api/core";
// Call the greet command
const message = await invoke("greet", { name: "World" });
console.log(message); // "Hello, World! From Rust."
// Call async command with error handling
try {
const content = await invoke("read_file", {
path: "/path/to/file.txt"
});
console.log(content);
} catch (error) {
console.error("Failed to read file:", error);
}
// Call stateful command
const newCount = await invoke("increment");
console.log("Count:", newCount);事件系统:Emit 与 Listen
事件系统提供 Rust 后端与 Web 前端之间的双向通信。事件适用于从 Rust 向前端推送数据(如进度更新或实时通知)以及窗口间通信。
事件可以全局发射(到所有窗口)或定向到特定窗口。前端可以监听 Rust 的事件,反之亦然。
// Rust: emitting events to the frontend
use tauri::{AppHandle, Emitter};
#[tauri::command]
async fn process_files(
app: AppHandle,
paths: Vec<String>
) -> Result<(), String> {
let total = paths.len();
for (i, path) in paths.iter().enumerate() {
// Process each file...
std::thread::sleep(
std::time::Duration::from_millis(100)
);
// Emit progress event to frontend
app.emit("progress", serde_json::json!({
"current": i + 1,
"total": total,
"file": path
})).map_err(|e| e.to_string())?;
}
Ok(())
}// Frontend: listening for events from Rust
import { listen } from "@tauri-apps/api/event";
import { invoke } from "@tauri-apps/api/core";
// Listen for progress events
const unlisten = await listen("progress", (event) => {
const { current, total, file } = event.payload;
console.log("Processing " + current + "/" + total
+ ": " + file);
updateProgressBar(current / total * 100);
});
// Start the process
await invoke("process_files", {
paths: ["/file1.txt", "/file2.txt"]
});
// Clean up listener when done
unlisten();窗口管理
Tauri 提供创建和管理应用窗口的完整 API。可以在配置文件中定义窗口,也可以从 Rust 或 JavaScript 在运行时动态创建。Tauri 2.0 还引入了在单个窗口内支持多个 web view 的多 webview API。
// Frontend: window management
import { WebviewWindow } from "@tauri-apps/api/webviewWindow";
import { getCurrentWindow } from "@tauri-apps/api/window";
// Create a new window
const webview = new WebviewWindow("settings", {
url: "/settings",
title: "Settings",
width: 600,
height: 400,
resizable: true,
center: true,
});
// Control the current window
const appWindow = getCurrentWindow();
await appWindow.setTitle("My Tauri App");
await appWindow.setSize({ width: 800, height: 600 });
await appWindow.center();
await appWindow.setAlwaysOnTop(true);
// Minimize, maximize, close
await appWindow.minimize();
await appWindow.toggleMaximize();
await appWindow.close();文件系统访问
Tauri 通过 fs 插件提供具有作用域安全模型的文件系统访问。不是给前端对整个文件系统的无限制访问,而是通过权限定义前端可以读写的目录和文件。
// Frontend: file system operations
import {
readTextFile, writeTextFile,
readDir, mkdir, remove
} from "@tauri-apps/plugin-fs";
import { appDataDir, join } from "@tauri-apps/api/path";
// Read a file from the app data directory
const dataDir = await appDataDir();
const configPath = await join(dataDir, "config.json");
const content = await readTextFile(configPath);
const config = JSON.parse(content);
// Write a file
await writeTextFile(
await join(dataDir, "output.txt"),
"Hello from Tauri!"
);
// List directory contents
const entries = await readDir(dataDir);
for (const entry of entries) {
console.log(entry.name, entry.isDirectory);
}
// Create a directory
await mkdir(await join(dataDir, "exports"), {
recursive: true
});插件:Store、SQL、HTTP、Shell
Tauri 2.0 使用插件架构,系统能力通过官方和社区插件提供。最常用的插件包括持久化存储、SQLite 数据库、HTTP 客户端和 Shell 命令执行。
Store 插件(持久化键值存储)
Store 插件提供基于 JSON 文件的简单持久化键值存储,适用于应用设置、用户偏好和需要跨会话持久化的小数据。
# Install the store plugin
npm run tauri add store
// Frontend: using the store plugin
import { load } from "@tauri-apps/plugin-store";
const store = await load("settings.json");
// Set values
await store.set("theme", "dark");
await store.set("fontSize", 14);
await store.set("user", {
name: "Alice",
email: "alice@example.com"
});
// Get values
const theme = await store.get("theme");
const user = await store.get("user");
// Persist to disk
await store.save();
// Listen for changes
await store.onChange((key, value) => {
console.log("Changed: " + key, value);
});SQL 插件(SQLite 数据库)
SQL 插件提供 SQLite 数据库用于结构化数据存储,支持迁移、参数化查询和多数据库连接。
# Install the SQL plugin
npm run tauri add sql
// Frontend: using the SQL plugin
import Database from "@tauri-apps/plugin-sql";
// Connect to SQLite database
const db = await Database.load(
"sqlite:app.db"
);
// Create table
await db.execute(
"CREATE TABLE IF NOT EXISTS notes ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "title TEXT NOT NULL, "
+ "content TEXT, "
+ "created_at DATETIME DEFAULT CURRENT_TIMESTAMP)"
);
// Insert data with parameters
await db.execute(
"INSERT INTO notes (title, content) VALUES (?, ?)",
["My Note", "Hello from Tauri SQL"]
);
// Query data
const notes = await db.select(
"SELECT * FROM notes WHERE title LIKE ?",
["%My%"]
);HTTP 插件
HTTP 插件允许前端通过 Rust 后端发起 HTTP 请求,绕过 CORS 限制并使用系统证书。
# Install the HTTP plugin
npm run tauri add http
// Frontend: making HTTP requests
import { fetch } from "@tauri-apps/plugin-http";
// GET request (bypasses CORS)
const response = await fetch(
"https://api.example.com/data",
{ method: "GET" }
);
const data = await response.json();
// POST request with JSON body
const result = await fetch(
"https://api.example.com/submit",
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ key: "value" })
}
);Shell 插件
Shell 插件允许生成子进程和执行系统命令,通过作用域权限控制允许的命令。
# Install the shell plugin
npm run tauri add shell
// Frontend: executing shell commands
import { Command } from "@tauri-apps/plugin-shell";
// Run a command and get output
const output = await Command.create(
"git", ["status", "--short"]
).execute();
console.log("stdout:", output.stdout);
console.log("stderr:", output.stderr);
// Stream output from long-running command
const cmd = Command.create("ping", ["localhost"]);
cmd.on("close", (data) => {
console.log("Exited with code", data.code);
});
cmd.stdout.on("data", (line) => {
console.log("Output:", line);
});
const child = await cmd.spawn();安全模型与权限
安全是 Tauri 的核心设计原则。框架实现了纵深防御策略:Rust 后端与 webview 前端的进程隔离、细粒度权限系统、CSP 强制执行以及基于作用域的文件系统限制。
Tauri 2.0 中,v1 的 allowlist 已被更强大的权限系统取代。每个插件定义自己的权限,在配置文件中显式授予前端对特定能力的访问。
// src-tauri/capabilities/main.json
// Define what the frontend window can access
{
"identifier": "main-capability",
"description": "Main window permissions",
"windows": ["main"],
"permissions": [
"core:default",
"fs:default",
"fs:allow-read-text-file",
"fs:allow-write-text-file",
{
"identifier": "fs:scope",
"allow": [
{ "path": "\$APPDATA/**" },
{ "path": "\$DOWNLOAD/**" }
]
},
"store:default",
"sql:default",
"shell:allow-execute",
{
"identifier": "shell:allow-spawn",
"allow": [
{ "cmd": "git", "args": true },
{ "cmd": "node", "args": ["--version"] }
]
},
"http:default",
{
"identifier": "http:scope",
"allow": [
{ "url": "https://api.example.com/**" }
]
}
]
}自动更新
Tauri 通过 updater 插件内置自动更新机制,支持差量更新、签名验证和自定义更新端点。更新器检查远程服务器的新版本并在后台下载更新。
// tauri.conf.json - updater configuration
{
"plugins": {
"updater": {
"pubkey": "YOUR_PUBLIC_KEY_HERE",
"endpoints": [
"https://releases.example.com/"
+ "{{target}}/{{arch}}/{{current_version}}"
],
"windows": {
"installMode": "passive"
}
}
}
}
// Frontend: check for updates
import { check } from "@tauri-apps/plugin-updater";
const update = await check();
if (update) {
console.log("Update available: " + update.version);
// Download and install
await update.downloadAndInstall();
// Restart the app to apply
await import("@tauri-apps/plugin-process")
.then(p => p.relaunch());
}构建与分发
Tauri 为每个目标平台生成原生应用包。Windows 生成 MSI 和 NSIS 安装程序,macOS 创建 DMG 和应用包,Linux 生成 AppImage 和 deb 包。通过 GitHub Actions 支持交叉编译。
# Build for the current platform
npm run tauri build
# Output locations:
# Windows: src-tauri/target/release/bundle/
# msi/MyApp_1.0.0_x64.msi
# nsis/MyApp_1.0.0_x64-setup.exe
#
# macOS: src-tauri/target/release/bundle/
# dmg/MyApp_1.0.0_aarch64.dmg
# macos/MyApp.app
#
# Linux: src-tauri/target/release/bundle/
# appimage/MyApp_1.0.0_amd64.AppImage
# deb/MyApp_1.0.0_amd64.deb
# Build with debug info
npm run tauri build -- --debug
# Build for a specific target
npm run tauri build -- --target aarch64-apple-darwin移动端支持:iOS 和 Android
Tauri 2.0 带来一等移动端支持,可以从桌面同一代码库构建 iOS 和 Android 应用。移动运行时在 iOS 上使用 WKWebView,Android 上使用 Android WebView,平台特定代码分别用 Swift 和 Kotlin 编写。
移动应用通过 Tauri 插件访问相机、GPS、生物识别和推送通知等原生设备功能。开发工作流支持 iOS 模拟器和 Android 模拟器的热重载。
# Initialize mobile targets
npm run tauri android init
npm run tauri ios init
# Development with hot-reload
npm run tauri android dev
npm run tauri ios dev
# Build for mobile
npm run tauri android build
npm run tauri ios build
# Platform-specific plugin (Swift for iOS)
// swift/Sources/ExamplePlugin.swift
// import Tauri
// class ExamplePlugin: Plugin {
// @objc func getBatteryLevel(
// _ invoke: Invoke
// ) {
// let level = UIDevice.current
// .batteryLevel
// invoke.resolve(["level": level])
// }
// }前端框架集成
Tauri 与前端框架无关,支持任何输出 HTML、CSS 和 JavaScript 的框架。最流行的选择是 React、Vue、Svelte 和 SolidJS,均可通过 create-tauri-app 直接脚手架。
// React + Tauri example
import { useState } from "react";
import { invoke } from "@tauri-apps/api/core";
function App() {
const [result, setResult] = useState("");
const [name, setName] = useState("");
async function handleGreet() {
const msg = await invoke("greet", { name });
setResult(msg);
}
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter a name"
/>
<button onClick={handleGreet}>Greet</button>
<p>{result}</p>
</div>
);
}<!-- Vue + Tauri example -->
<script setup lang="ts">
import { ref } from "vue";
import { invoke } from "@tauri-apps/api/core";
const name = ref("");
const result = ref("");
async function greet() {
result.value = await invoke("greet", {
name: name.value
});
}
</script>
<template>
<input v-model="name" placeholder="Enter a name" />
<button @click="greet">Greet</button>
<p>{{ result }}</p>
</template><!-- Svelte + Tauri example -->
<script>
import { invoke } from "@tauri-apps/api/core";
let name = "";
let result = "";
async function greet() {
result = await invoke("greet", { name });
}
</script>
<input bind:value={name} placeholder="Enter a name" />
<button on:click={greet}>Greet</button>
<p>{result}</p>性能与包体积
Tauri 在所有关键指标上都优于 Electron。以下是最大化性能的最佳实践:
- 使用操作系统原生 webview 而非捆绑浏览器引擎,保持二进制大小低于 5 MB。
- 将 CPU 密集型工作转移到 Rust 命令,而非在 JavaScript 中运行,可显著提升速度。
- 使用事件系统进行实时数据推送,而非轮询式的 invoke 调用。
- 将文件系统权限限定在应用所需的目录,以减少攻击面。
- 启用带差量更新的 updater 插件,最小化用户的下载大小。
- 轻量键值数据使用 Store 插件,结构化数据使用 SQL 插件,避免文件存储。
- 利用 Tauri 资源系统捆绑 Rust 后端需要访问的静态资源。
- 配置 CSP 头部防止 XSS 攻击,限制 webview 可加载的资源。
// Example: offload heavy work to Rust for performance
// Instead of processing in JavaScript:
// const result = heavyComputation(data); // Slow in JS
// Define a Rust command for the heavy work
// src-tauri/src/lib.rs
#[tauri::command]
fn process_data(input: Vec<f64>) -> Vec<f64> {
input.iter()
.map(|x| x.sqrt() * 2.0 + x.ln())
.collect()
}
// Call from frontend - runs at native speed
// const result = await invoke("process_data", {
// input: largeDataSet
// });常见问题
Tauri 用来做什么?
Tauri 用于构建跨平台桌面应用,常见用例包括开发者工具、生产力应用、仪表盘、媒体播放器、文件管理器和系统工具。Tauri 2.0 还支持 iOS 和 Android 移动应用。
Tauri 比 Electron 好吗?
Tauri 产生的二进制文件更小(3-5 MB vs 150+ MB)、内存更低、安全模型更强。但 Electron 生态更大、工具更成熟、跨平台渲染一致性更好。追求性能和安全选 Tauri,追求浏览器 API 兼容性选 Electron。
使用 Tauri 需要会 Rust 吗?
基础 Tauri 应用只需少量 Rust 知识,脚手架工具会生成样板代码。但随着应用增长,需要 Rust 编写自定义命令、系统集成和性能关键的后端逻辑。
Tauri 支持哪些前端框架?
Tauri 支持任何输出 HTML/CSS/JS 的前端框架。官方脚手架模板包括 React、Vue、Svelte、SolidJS、Angular、Preact、原生 JS 和 TypeScript。也可以使用 Next.js、Nuxt 等元框架的静态导出模式。
Tauri 支持移动端吗?
支持。Tauri 2.0 引入了 iOS 和 Android 一等支持,可从同一代码库构建移动应用,通过 Tauri 插件访问原生设备功能。
Tauri 如何处理自动更新?
Tauri 内置 updater 插件检查远程端点的新版本,支持签名验证、差量更新和自定义更新端点。在 tauri.conf.json 中配置更新 URL 和公钥。
Tauri 可以用于生产吗?
可以。Tauri 2.0 已稳定并被许多公司在生产环境使用。CrabNebula Cloud、Clash Verge、Pake 等知名应用都基于 Tauri 构建。
如何在 Tauri 中访问文件系统?
Tauri 通过 fs 插件提供具有作用域权限的文件系统访问。在能力配置中定义应用可访问的目录,然后前端使用插件 API 在这些作用域内读写文件。