Rust 跨平台 GUI 开发:`tauri` 框架与 Web 技术的融合合
目录
3.3 步骤 3:实现 Rust 后端Commands & Events)
📝 文章摘要
Tauri 是一个使用 Rust 构建跨平台桌面应用的新一代框架。它巧妙地结合了 Rust 的高性能后端和eb 前端技术(HTML/CSS/JS),替代了 Electron 的 Node.js 运行时,提供了体积更小、内存占用更低、安全性更高的桌面应用。本文将深入探讨 Tauri v2 的架构、其 Rust 后端与 JavaScript 前端的通信机制(Events、Commands),以及如何打包跨平台(Windows, macOS, Linux)的单一二进制应用。我们将实战构建一个系统监控工具,展示 Rust 如何赋能现代桌面开发。
一、背景介绍
1.1 Electron 的困境
Electron(如 VS Code, Slack)通过捆绑 Node.js 和 Chromium 实现了跨平台 GUI。但其代价高昂:
- 内存占用大:每个应用都包含一个完整的浏览器实例,内存动辄 300MB+。
- 体积庞大:应用打包后体积巨大(>100MB)。
- **性能瓶*:Node.js 后端存在 GC 和单线程限制。
1.2 Tauri:Rust 的解决方案
Tauri v2 采用了一种更轻量级的混合架构:
-
Rust 核心:负责所有原生逻辑、系统 API 调用、文件系统和计算。
-
系统 WebView:使用操作系统内置的 Web 渲染引擎(Windows 的 WebView2, macOS 的 WKWebView, Linux 的 WebKitGTK)。
-
JS/TS 前端:使用 React, Vue, Svelte 等任意前端框架构建 UI。
Tauri 优势:极小的二进制体积、极低的内存占用、Rust 的安全与高性能。
二、原理详解
2.1 Tauri 架构
Tauri 的核心是一个 Rust 进程,它创建并管理一个或多个 WebView 窗口。

2.2 核心通信:Commands
Commands 是从 JavaScript 调用 Rust 函数的机制。
1. Rust (后端) 定义 Command:
使用 #[tauri::command] 宏,它会自动生成将 Rust 函数暴露给前端的 IPC 绑定。
// src-tauri/src/main.rs
// 这是一个 Tauri Command
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
**2JavaScript (前端) 调用 Command:**
Tauri 的 JS API (@tauri-apps/api) 提供了 invoke 函数。
// src/main.js
import { invoke } from '@tauri-apps/api/tauri';
async function Greet() {
// 调用 Rust 后端的 "greet" command
const response = await invoke('greet', { name: 'World' });
console.log(response); // "Hello, World! You've been greeted from Rust!"
}
2.3 核心通信:Events
Events 允许 Rust 后端主动向 JavaScript 前端推送数据,非常适合实时更新。
1. Rust (后端) 发送 Event:
// src-tauri/src/main.rs
use tauri::{Window, Manager};
fn emit_system_stats(window: Window) {
std::thread::spawn(move || {
loop {
// 模拟获取 CPU 使用率
let cpu_usage = (rand::random::::<f64>() * 100.0).floor();
// 向所有窗口广播 "system-stats" 事件
window.emit("ystem-stats", cpu_usage).unwrap();
std::thread::sleep(std::time::Duration::from_secs(1)); }
});
}
2. JavaScript (前端) 监听 Event:
// src/main.js
importrt { listen } from '@tauri-apps/api/event';
async function setupListener() {
// 监听 "system-stats" 事件
const unlisten = await listen('system-stats', (event) => {
console.log('CPU Usage:', event.payload);
// 更新 UIe.g., setCpuUsage(event.payload))
});
// 可以在组件卸载时调用 unlisten() 来停止监听
}
三、代码实战:系统监控 TUI
我们将构建一个简单的跨平台应用,实时显示 CPU 和内存使用率。
3.1 步骤 1:初始化 Tauri + React
# 1. 安装 Tauri CLI
cargo install tauri-cli
# 2. 使用模板创建项目 (我们选择 React + TS)
cargo create-tauri-app
# ? App name: system-monitor
# ? Frontend: React (Vite)
# ? UI Template: TypeScript
cd system-monitor
npm install # 安装前端依赖
项目结构:
system-monitor/
├── src/ # React 前端代码
│ ├── main.tsx
│ └── App.tsx
├── src-tauri/ # Rust 后端代码
│ ├── Cargo.toml
│ ├── tauri.conf.json # Tauri 配置
│ └── src/
│ └── main.rs
3.2 步骤 2:配置配置 tauri.conf.json
我们需要允许 Rust 访问系统信息(这是一个特权操作)。
src-tauri/taurif.json (部分):
{
"tauri": {
"allowlist": {
"all":false, // 默认关闭所有
"shell": {
"all": false,
"open": true // 允许打开链接
},
"event": {
"emit": true, // 允许 Rust -> JS 事件
"listen": true // 允许 JS -> Rust 事件
},
"fs": {
"all": false
},
"window": {
"all": true // 允许窗口操作
}
},
// ...
}
}
注意:Tauri 默认是安全的。的。访问文件系统、执行 shell 命令等都需要在 allowlist 中显式开启。
3.3 步骤 3:实现 Rust 后端Commands & Events)
我们需要 systemstat 库来获取系统信息。
src-tauri/Cargo.toml (添加依赖):
[dependencies]
tauri = { version = "2.0.0-beta", features = [] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
systemstat = "0.22.3" # 获取系统信息
src-tauri/src/main.rs
// Prevents additionalconsole window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use serde::Serialize;
use systemstat::{System, Platform, saturating_sub_bytes};
use tauri::{Manager, Window};
use std::time::Duration;
// 1. 定义 Command:获取一次性系统信息
#[derive(Serialize, Clone)]
struct SystemInfo {
os_name: String,
cpu_model: String,
total_memory_gb: f32,
}
#[tauri::command]
fn get_system_info(sys: tauri::State<System>) -> SystemInfo {
let mem = sys.memory().unwrap();
SystemInfo {
os_name: System::os_name().unwrap_or_default(),
cpu_model: sys.cpu_load_aggregate().unwrap().core_name,
total_memory_gb: mem.total.as_GB() as f32,
}
}
// 2. 定义 Event 负载:实时统计
#[derive(Serialize, Clone)]
struct LiveStats {
cpu_usage_percent: f32,
memory_used_gb: f32,
}
// 3. 启动实时统计的后台线程
fn start_stats_emitter(window: Window) {
let sys = System::new();
std::thread::spawn(move || {
loop {
// 获取 CPU
let cpu_load = sys.cpu_load_aggregate().unwrap().done().unwrap();
// 获取内存
let mem = sys.memory().unwrap();
let mem_used = saturating_sub_bytes(mem.total, mem.free);
let stats = LiveStats {
cpu_usage_percent: (cpu_load.user + cpu_load..system) * 100.0,
memory_used_gb: mem_used.as_GB() as f32, };
// 发送事件
window.emit("live-stats", stats).unwrap();
std::thread::sleep(Duration::from_secs(1));
}
});
}
fn main() {
let sys = System::new(); // 创建系统状态
tauri::Builder::default()
// 1. 将 System 实例作为“状态”注入,供 Command 使用
.manage(sys)
// 2. 注册 Commands
.invoke_handler(tauri::generate_handler![get_system_info])
// 3. 在应用启动时,启动后台事件发射器
.setup(|app| {
let main_window = app.get_window("main").unwrapap();
start_stats_emitter(main_window);
Ok(())
})
.run(tauri::generate_context!)
.expect("error while running tauri application");
}
3.4 步骤 4:实现 React 前端 (UI)
src/App.tsx
import { useState, useEffect } from 'react';
import { invoke } from '@tauri-apps/api/tauri';
import { listen } from '@tauri-apps/api/event';
import './App.css';
// 匹配 Rust 后端的 SystemInfo
interface SystemInfo {
os_name: string;
cpu_model: string;
total_memory_gb: number;
}
// 匹配 Rust 后端的 LiveStats
interface LiveStats {
cpu_usage_percent: number;
memory_used_gb: number;
}
function App() {
const [info, setInfo] = useState<SystemInfo || null>(null);
const [stats, setStats] = useState<LiveStats | null>(null);
// 1. 启动时用 Command 获取静态信息
useEffect(() => {
invoke<SystemInfo>('get_system_info')
.then(setInfo)
.catch(console.error);
}, []);
// 2. 启动时监听 Event 获取实时数据
useEffect(() => {
let unlisten: () => void;
async function setupListener() {
unlisten = await listen<LiveStats>('live-stats', (event) => {
setStats(event.payload);
});
}
setupListener();
// 组件组件卸载时停止监听
return () => {
if (unlisten) unlisten();
};
}, []);
// 3.染 UI
return (
<div className="container">
<h1>Rust System Monitor (Tauri)</h1>
{info && (
<div className="card">
<h2>System Info</h2>
<p><strong>OS:</strong> {info.os_name}</p>
<p><strong>CPU:</strong> {info.cpu_model}</p>
<p><strong>Total Memory:</strong> {info.total_memory_gb.toFixed(2)} GB</p>
</div>
)}
{stats && (
<div className="card">
<h2>Live Stats</h2>
<p><strong>CPU Usage:</strong> {stats.cpu_usage_percent.toFixed(1)} %</p>
<p><strong>Memory Usage:</strong> {stats.memory_used_gb.toFixed(2)} GB</g>
</div>
)}
</div>
);
}
export default App;
四、结果分析
4.1 编译与打包
# 1. 开发模式 (实时热重载)
cargo tauri dev
# 2. 生产模式 (构建单一二进制安装包)
cargo tauri build
构建结果 (macOS 示例):
src-tauri/target/release/system-onitor(可执行文件): ~4.5 MBsrc-tauri/target/release/bundle/dmg/system-monitor...dmg(安装包): ~2.8 MB
| 框架 | 应用 (Hello World) | 内存占用 (Idle) |
|---|---|---|
| Electron | ~120 MB | ~150 MB |
| Tauri (v2) | ~5 MB | ~25 MB |
graph TD
A[应用体积对比] --> B(Electron (120 MB));
A --> C(Tauri (5 MB));
D[内存占用对比] --> E(Electron (150 MB));
D --> F(Tauri (25 MB));
style C fill:#e8f5e9,stroke:#388e3c
style F fill:#e8f5e9,stroke:#388e3c
分析:Tauri 应用的体积比 Electron 小了 24 倍,内存占用低了 6 倍。这是因为它复用了操作系统的 WebView,而 Electron 捆绑了整个 Chromium。
4.2 安全性分析
Tauri 的 allowlist 机制(默认全关闭)提供了“了“最小权限原则”。如果 tauri.conf.json 没有开启 fs(文件系统)权限,Rust 后端(即使被攻破)也无法用户文件,从根本上提高了安全性。
五、总结与讨论
5.1 核心要点
-
- Tauri 架构:Rust 后端 + 系统 WebView 前端。
-
低开销:实现了极小的二进制体积和内存占用。 * 通信机制:
#[tauri::command]:JS 调用 Rust (请求/响应)。- `windowemit()
/listen()`:Rust 推送数据到 JS (事件驱动)。
-
安全性:
allowlist强制执行最小权限,比 Node.js 后端更安全。 -
生态:可以使用任何 Web 前端框架(React, Vue, Svelte, Solid)构建 UI。
5.2 讨论问题
- Tauri 依赖“系统 WebView”是优点还是缺点?(提示:优点是体积小,缺点是跨平台 UI 可能存在细微差异)。
tauri::command的参数和返回值是如何通过serde自动序列化和反序列化的?- 在 Electron 中,前端和后端都是 JS。在 Tauri 中,前端 (JS) 和后端 (Rust) 的职责应该如何划分?
- Tauri v2 引入了移动端(iOS/Android)支持,这对 Rust 的跨平台生态意味着什么?
参考链接
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)