tauri::Builder 是 Tauri 应用的真正起点。它像是一个“装配流水线”,让你用链式调用的方式一步步配置窗口行为、注册插件、暴露 Rust 命令、注入共享状态,最后启动事件循环。整个初始化流程遵循一个清晰的模式:构建 → 配置 → 运行。
1. Builder 是什么?
在 Rust 的 main 函数中,你总是会看到类似这样的代码:
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![my_command])
.run(tauri::generate_context!())
.expect("启动应用失败");
}
tauri::Builder::default()创建一个默认的构建器,它已经包含了 WebView 窗口创建、IPC 通信、菜单管理等基础能力。- 随后你可以通过一系列
.xxx()方法进行定制。 - 最终
.run()会阻塞主线程,进入事件循环,等待窗口关闭或其他退出信号。
2. 核心配置方法
| 方法 | 用途 | 说明 |
|------|------|------|
| .invoke_handler(tauri::generate_handler![...]) | 注册 Rust 命令 | 将 Rust 函数暴露给前端调用,所有命令必须在此注册 |
| .manage(state) | 注入全局共享状态 | 比如数据库连接池、配置对象,任何命令都可以通过参数获取 |
| .setup(|app| { ... }) | 应用初始化钩子 | 在窗口创建前执行,适合加载插件、创建托盘、初始化系统 |
| .plugin(tauri_plugin_xxx::init()) | 安装 Tauri 官方/社区插件 | 快速集成日志、存储、对话框等功能,一行代码搞定 |
| .menu(menu) | 设置原生菜单 | 配合系统托盘或主窗口使用 |
| .on_window_event(|window, event| { ... }) | 监听窗口事件 | 如关闭、获得焦点等 |
3. 实际初始化流程示例
下面是一个更完整的例子,展示了典型的小型工具应用的 Builder 配置:
use tauri::Manager;
// 定义全局状态
struct AppConfig {
app_name: String,
}
// 一个简单的 Rust 命令
#[tauri::command]
fn greet(name: &str) -> String {
format!("你好, {}!", name)
}
fn main() {
// 初始化数据库连接池、读取配置等(如果耗时,可异步)
let config = AppConfig {
app_name: "MyTool".into(),
};
tauri::Builder::default()
// 注入状态,使命令和 setup 中都能访问
.manage(config)
// 注册所有暴露给前端的命令
.invoke_handler(tauri::generate_handler![greet])
// 添加官方插件,例如日志和存储
.plugin(tauri_plugin_log::Builder::default().build())
.plugin(tauri_plugin_store::Builder::default().build())
// 启动前执行:创建系统托盘、请求权限等
.setup(|app| {
// 可以通过 app.handle() 获取 AppHandle,发送事件等
let _window = app.get_window("main").unwrap();
// 设置托盘图标和菜单(这里略)
Ok(())
})
// 监听窗口关闭事件(例如保存数据)
.on_window_event(|event| {
if let tauri::WindowEvent::CloseRequested { .. } = event.event() {
// 执行清理工作
}
})
// 加载 tauri.conf.json 配置并启动
.run(tauri::generate_context!())
.expect("应用启动失败");
}
4. 流程关键点说明
1) generate_context! 宏
它读取项目根目录下的 tauri.conf.json,解析出窗口标题、尺寸、允许的 API 权限等配置,传递给 Builder。没有它,Tauri 不知道要创建什么样的窗口。
2) 命令注册必须在 run 之前
Rust 的 #[tauri::command] 标记的函数,必须通过 tauri::generate_handler! 宏注册到 Builder。前端调用 invoke('command_name') 时,Tauri 会在这个注册表中查找对应函数。
3) setup 钩子是单向的
它返回 Ok(()) 表示初始化成功,然后窗口才会真正创建。严格来说,setup 中不应该执行会阻塞很久的任务(否则窗口迟迟不出现),但可以安排异步任务。
4) .manage 与命令参数
注入的状态类型必须满足 Send + Sync。在命令函数中,可以直接通过参数获取:
#[tauri::command]
fn setup_info(config: tauri::State<AppConfig>) -> String {
config.app_name.clone()
}
Tauri 会自动根据类型从托管池中取出引用,无需手动提取。
5) .run() 是最终调用
调用后,控制权交给 Tauri 的事件循环,主线程会阻塞直到所有窗口关闭。这也是为什么通常 main 函数的最后一行就是 .run()。
5. 最小的“Hello World”初始化
如果你只是想看最简单的启动代码,就是:
fn main() {
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
这会根据 tauri.conf.json 创建一个窗口并加载你构建后的前端资源(默认 ../dist 目录),不需要任何命令或状态。
总结:tauri::Builder 的初始化流程始终遵循“注册资源 → 配置行为 → 启动事件循环”的步骤。这种模式让你可以按需添加功能,而不会出现隐藏的全局状态,也让测试和拆分插件变得容易。