前言
Tauri 是一个使用 Web 技术构建桌面应用的框架,相比 Electron,它的优势在于:
- 体积小:打包后仅几 MB,而 Electron 动辄上百 MB
- 性能高:使用 Rust 作为后端,内存占用低
- 安全性强:默认禁用 Node.js,减少攻击面
本文将带你从零构建一个完整的 Tauri 应用,包含前后端通信的实战案例。
一、环境准备
1.1 安装 Rust
Windows 用户下载并运行 rustup-init.exe,按提示完成安装。
安装完成后验证:
rustc --version
cargo --version
1.2 安装 Node.js
推荐使用 Node.js 18 或更高版本。
node --version
npm --version
1.3 安装系统依赖
Windows 需要安装:
- Microsoft Visual Studio C++ Build Tools
- WebView2(Windows 10/11 通常已预装)
二、创建项目
2.1 初始化 Tauri 项目
npm create tauri-app@latest
按提示选择:
✔ Project name · my-tauri-app
✔ Identifier · com.example.app
✔ Choose which language to use for your frontend · TypeScript / JavaScript
✔ Choose your package manager · npm
✔ Choose your UI template · React
✔ Choose your UI flavor · TypeScript
2.2 进入项目并安装依赖
cd my-tauri-app
npm install
2.3 项目结构
my-tauri-app/
├── src/ # React 前端代码
│ ├── App.tsx
│ ├── main.tsx
│ └── ...
├── src-tauri/ # Rust 后端代码
│ ├── src/
│ │ ├── lib.rs # 主要逻辑
│ │ └── main.rs # 入口文件
│ ├── Cargo.toml # Rust 依赖配置
│ └── tauri.conf.json # Tauri 配置文件
├── package.json
└── ...
2.4 启动开发服务器
npm run tauri dev
首次运行会编译 Rust 代码,需要等待几分钟。之后会弹出应用窗口。
三、前后端通信:核心概念
Tauri 的前后端通信主要通过 Commands(命令) 实现:
- Rust 端:定义命令函数,处理业务逻辑
- React 端:调用命令,获取返回值
这是 Tauri 最核心的功能,下面通过实战案例讲解。
四、实战案例:获取系统信息
我们来实现一个获取系统磁盘信息的功能。
4.1 Rust 端:定义命令
编辑 src-tauri/src/lib.rs:
use serde::Serialize;
// 定义返回数据结构
#[derive(Debug, Serialize)]
pub struct DiskInfo {
pub drive_letter: String,
pub total_space: u64,
pub free_space: u64,
pub used_space: u64,
pub usage_percent: f64,
}
// 定义 Tauri 命令
#[tauri::command]
fn get_disk_info() -> Result<DiskInfo, String> {
// 这里简化处理,实际可以使用 sysinfo 库获取真实数据
let total: u64 = 500 * 1024 * 1024 * 1024; // 500GB
let free: u64 = 100 * 1024 * 1024 * 1024; // 100GB
let used = total - free;
Ok(DiskInfo {
drive_letter: "C".to_string(),
total_space: total,
free_space: free,
used_space: used,
usage_percent: (used as f64 / total as f64) * 100.0,
})
}
// 注册命令
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![get_disk_info]) // 注册命令
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
关键点:
#[tauri::command]宏将函数标记为可被前端调用的命令- 返回值需要实现
Serializetrait - 使用
Result<T, String>可以向前端返回错误信息 - 必须在
invoke_handler中注册命令
4.2 添加 Rust 依赖
编辑 src-tauri/Cargo.toml,确保有 serde 依赖:
[dependencies]
tauri = { version = "2", features = [] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
4.3 React 端:调用命令
编辑 src/App.tsx:
import { useState } from 'react';
import { invoke } from '@tauri-apps/api/core';
// 定义类型(与 Rust 端对应)
interface DiskInfo {
drive_letter: string;
total_space: number;
free_space: number;
used_space: number;
usage_percent: number;
}
function App() {
const [diskInfo, setDiskInfo] = useState<DiskInfo | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// 调用 Rust 命令
const fetchDiskInfo = async () => {
setLoading(true);
setError(null);
try {
// invoke 函数调用 Rust 命令,命令名使用蛇形命名法
const info = await invoke<DiskInfo>('get_disk_info');
setDiskInfo(info);
} catch (err) {
setError(String(err));
} finally {
setLoading(false);
}
};
// 格式化文件大小
const formatSize = (bytes: number): string => {
const gb = bytes / (1024 * 1024 * 1024);
return `${gb.toFixed(2)} GB`;
};
return (
<div style={{ padding: '20px' }}>
<h1>Tauri 磁盘信息示例</h1>
<button onClick={fetchDiskInfo} disabled={loading}>
{loading ? '加载中...' : '获取磁盘信息'}
</button>
{error && (
<p style={{ color: 'red' }}>错误: {error}</p>
)}
{diskInfo && (
<div style={{ marginTop: '20px' }}>
<p><strong>盘符:</strong> {diskInfo.drive_letter}:</p>
<p><strong>总容量:</strong> {formatSize(diskInfo.total_space)}</p>
<p><strong>已用:</strong> {formatSize(diskInfo.used_space)}</p>
<p><strong>可用:</strong> {formatSize(diskInfo.free_space)}</p>
<p><strong>使用率:</strong> {diskInfo.usage_percent.toFixed(1)}%</p>
</div>
)}
</div>
);
}
export default App;
关键点:
- 使用
@tauri-apps/api/core中的invoke函数调用命令 - 命令名需要使用蛇形命名法(snake_case)
- 泛型参数指定返回值类型
- 使用 try-catch 处理可能的错误
4.4 运行测试
npm run tauri dev
点击按钮,即可看到从 Rust 端返回的磁盘信息。
五、进阶:带参数的命令
5.1 Rust 端
#[tauri::command]
fn greet(name: String) -> String {
format!("Hello, {}! Welcome to Tauri.", name)
}
// 记得注册
.invoke_handler(tauri::generate_handler![get_disk_info, greet])
5.2 React 端
const greeting = await invoke<string>('greet', { name: 'Tauri' });
console.log(greeting); // "Hello, Tauri! Welcome to Tauri."
注意: 参数以对象形式传递,键名必须与 Rust 函数参数名一致。
六、进阶:异步命令
对于耗时操作,使用异步命令避免阻塞:
#[tauri::command]
async fn scan_files(path: String) -> Result<Vec<String>, String> {
// 模拟耗时操作
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
Ok(vec![
format!("{}/file1.txt", path),
format!("{}/file2.txt", path),
])
}
需要在 Cargo.toml 添加 tokio 依赖:
[dependencies]
tokio = { version = "1", features = ["time"] }
七、配置应用信息
编辑 src-tauri/tauri.conf.json:
{
"productName": "我的应用",
"version": "1.0.0",
"identifier": "com.example.myapp",
"build": {
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"title": "我的 Tauri 应用",
"width": 900,
"height": 600,
"resizable": true,
"center": true
}
]
}
}
八、打包发布
8.1 执行打包命令
npm run tauri build
8.2 打包产物
打包完成后,安装包位于:
src-tauri/target/release/bundle/
├── msi/ # MSI 安装包
│ └── 应用名_版本_x64_en-US.msi
└── nsis/ # NSIS 安装包
└── 应用名_版本_x64-setup.exe
8.3 常见问题:网络超时
如果遇到 timeout: global 错误,是因为下载 NSIS 工具超时。
解决方案:手动下载 NSIS 并放到缓存目录。
# 创建目录
New-Item -ItemType Directory -Path "$env:LOCALAPPDATA\tauri\NSIS" -Force
# 手动下载 nsis-3.zip 并解压到上述目录
九、总结
本文介绍了 Tauri 2.0 的核心开发流程:
- 环境搭建:安装 Rust 和 Node.js
- 项目创建:使用脚手架快速初始化
- 前后端通信:通过 Commands 实现 React 与 Rust 的数据交互
- 打包发布:生成 Windows 安装包
Tauri 的优势在于小体积、高性能、强安全性,非常适合开发轻量级桌面工具。希望这篇教程能帮助你快速上手 Tauri 开发!