命令的本质
一个 Tauri 命令就是一个普通的 Rust 函数,加上 #[tauri::command] 属性标记。它可以接收参数、返回结果,甚至是以异步方式运行。Tauri 会自动将这些函数注册为 IPC 可调用命令,前端通过 @tauri-apps/api 中的 invoke 方法以命令名字符串进行调用。
创建第一个命令
假设你需要一个功能:根据传入的文件路径,读取文本内容并返回。你可以在 Rust 中这样写:
// src-tauri/src/main.rs 或独立的 commands.rs
#[tauri::command]
fn read_file_content(path: String) -> Result<String, String> {
std::fs::read_to_string(&path).map_err(|e| e.to_string())
}
这段代码非常朴素:接收一个 String 参数,尝试读取文件,成功返回内容,失败以 Err(String) 形式返回错误信息。
注册命令
光有函数还不够,你需要把它告诉 Tauri 应用。在 main 函数中的构建阶段使用 .invoke_handler 进行注册:
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![read_file_content])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
tauri::generate_handler! 宏会为你生成一个命令调度器,将命令名字符串映射到对应的 Rust 函数。
前端调用
在前端,无论是 React、Vue 还是原生 JS,你都可以通过 invoke 调用这个命令:
import { invoke } from '@tauri-apps/api/tauri';
const content = await invoke('read_file_content', { path: '/Users/name/test.txt' });
console.log(content);
注意命令名是蛇形命名(snake_case),即 Rust 函数名本身,Tauri 会自动转换为对应的字符串标识。
传递复杂参数
Rust 命令的参数可以使用任何实现了 serde::Deserialize 的类型,返回值则需要实现 serde::Serialize。对于结构体,只需添加对应的 derive:
#[derive(serde::Deserialize)]
struct UserInput {
name: String,
age: u8,
}
#[tauri::command]
fn save_user(user: UserInput) -> Result<(), String> {
// 存储逻辑...
Ok(())
}
前端调用时,直接传递匹配结构体的对象即可:
await invoke('save_user', { user: { name: 'Alice', age: 30 } });
异步命令
如果你的命令涉及耗时操作(如网络请求、大量计算),建议将其定义为异步函数,避免阻塞主线程。只需将函数标记为 async 即可,Tauri 会自动在异步运行时中执行:
#[tauri::command]
async fn fetch_data(url: String) -> Result<String, String> {
let resp = reqwest::get(&url)
.await
.map_err(|e| e.to_string())?;
let body = resp.text().await.map_err(|e| e.to_string())?;
Ok(body)
}
前端调用异步命令的写法完全一样,invoke 返回的是 Promise。
访问 Tauri 应用状态
有时命令需要访问应用级的状态(如数据库连接、配置)。可以使用 tauri::State 注入:
use tauri::State;
use std::sync::Mutex;
struct AppState {
db: Mutex<Option<Database>>,
}
#[tauri::command]
fn query_db(state: State<AppState>, sql: String) -> Result<String, String> {
let db = state.db.lock().map_err(|e| e.to_string())?;
// 执行查询...
}
状态需要在 main 中通过 .manage(...) 注入。
权限控制
Tauri v2 增加了更严格的权限系统。自定义命令默认需要显式授权。你需要在 capabilities 配置中声明哪些命令允许前端调用,例如在 src-tauri/capabilities/default.json 中添加:
{
"identifier": "default",
"windows": ["main"],
"permissions": [
"core:default",
"your-command-identifier:allow"
]
}
这一步看似繁琐,却是“安全优先”思想的具体落地:即使你写了很多命令,前端也无法调用未授权的命令,有效防止攻击面扩大。
一句话总结:自定义 Rust 命令让前端能够安全、高效地调用原生能力,是 Tauri 应用开发中最频繁使用的功能。只需编写普通 Rust 函数、注册、授权,就能在 JavaScript 中以 invoke 方式访问,整个过程类型安全且清晰明了。