Skip to content

Tauri 参考

基于 Tauri 2.x · 核于 2026-07

速查

  • 版本:Tauri v2(2.0 stable);CLI @tauri-apps/cli v2.x;底层 WRY ≈0.55.x / TAO ≈0.35.x;GitHub ≈107–108k star;MSRV Rust 1.77.2
  • 架构:Core(Rust) + WRY / TAO + 系统 WebView;依赖链 tauritauri-runtimetauri-runtime-wry → WRY → TAO
  • 最常踩:v1 allowlist 已废改 ACL;逻辑在 lib.rsmain.rs 是薄壳;命令 pub 规则;async 命令禁借用参数;Emitter/Manager trait;Channel 用 new Channel()

一、版本坐标

主版本Tauri v2(2.0 stable)
CLI@tauri-apps/cli v2.x
底层 WRY≈0.55.x(WebView 封装)
底层 TAO≈0.35.x(窗口库,fork 自 winit)
GitHub star≈107–108k(2026-07)
MSRVRust 1.77.2
平台Linux / macOS / Windows + iOS / Android

二、核心 API 速记

场景API
定义命令#[tauri::command] fn foo(...) -> T {}
注册命令.invoke_handler(tauri::generate_handler![foo, bar])
前端调命令import { invoke } from '@tauri-apps/api/core'; invoke('foo', { arg })
参数命名默认 camelCase;#[tauri::command(rename_all = "snake_case")]
错误处理返回 Result<T, E>(E 实现 Serialize,用 thiserror)→ 前端 .catch
async 命令async fn;禁借用参数,可返回 Result<T, ()>
大二进制返回tauri::ipc::Response::new(bytes)
Rust 发事件use tauri::Emitter; app.emit("ev", payload) / emit_to("label", ...)
前端听事件import { listen, once } from '@tauri-apps/api/event'; const un = await listen('ev', cb)
高吞吐流tauri::ipc::Channel<T>(后端 .send())+ 前端 new Channel()
注册状态.manage(Mutex::new(state))
取状态(命令内)state: State<'_, Mutex<T>>state.lock().unwrap()
取状态(命令外)app.state::<Mutex<T>>()(需 use tauri::Manager
取窗口app.get_webview_window("main")(需 use tauri::Manager
注册插件.plugin(tauri_plugin_fs::init())

三、关键 CLI

bash
npm create tauri-app@latest            # 脚手架(交互式选前端/语言/包管理器)
npm run tauri dev / build              # 桌面开发 / 构建
npm run tauri build --no-bundle        # 只编不打包
npm run tauri android|ios init|dev|build   # 移动端
npm run tauri signer generate -- -w key    # 生成更新签名密钥
rustc --print host-tuple               # 查目标三元组(sidecar 命名用)

四、权限标识符速记

  • core(内置)core:defaultcore:window:allow-closecore:event:defaultcore:path:default
  • 插件fs:defaultfs:read-filesfs:allow-mkdirfs:scope-homeshell:allow-executeshell:allow-spawnupdater:defaultdialog:defaultnotification:default
  • 移动biometric:allow-authenticatenfc:allow-scan
  • 规则<插件>:<allow|deny>-<命令><插件>:defaultdeny > allowtauri-plugin- 前缀自动补全;标识符限 ASCII 小写、长度 ≤116

五、配置骨架(tauri.conf.json)

json
{
  "productName": "MyApp",
  "version": "1.0.0",
  "identifier": "com.example.myapp",
  "build": {
    "beforeDevCommand": "npm run dev",
    "devUrl": "http://localhost:3000",
    "beforeBuildCommand": "npm run build",
    "frontendDist": "../dist"
  },
  "app": {
    "windows": [{ "title": "Main" }],
    "security": { "csp": "default-src 'self'", "capabilities": ["main-capability"] }
  },
  "bundle": { "active": true, "targets": "all", "icon": ["icons/icon.png"] },
  "plugins": { "updater": { "pubkey": "...", "endpoints": ["..."] } }
}

六、vs Electron 对照

维度Tauri v2Electron
后端语言Rust(移动可 Swift/Kotlin)Node.js
渲染引擎系统 WebView打包 Chromium
安装包极小(<600KB~10MB)大(100MB+)
内存低(~50MB 级)
渲染一致性各 OS 有差异一致
移动端支持 iOS/Android不支持
生态较新、增长快老牌、最全

七、高频坑 / 考点

#要点
1v1→v2allowlist 已废,改 Permissions/Capabilities ACL;核心 API 拆成 tauri-plugin-*
2入口:逻辑在 lib.rsrun()main.rs 是薄壳;移动靠 mobile_entry_point
3命令 pub 规则lib.rs 内命令不能 pub;独立模块内必须 pub
4async 命令:不能收借用参数(&str / State<'_>
5参数命名:Rust snake_case ↔ 前端默认 camelCase
6两个 traitapp.emituse tauri::Emitterapp.state()/get_webview_window()use tauri::Manager
7Channel:前端用 new Channel() 对象作 invoke 参数传入
8远程 IPC:默认禁远程调 API;Linux/Android 无法区分 iframe 与主窗口
9Isolation:Windows 下不支持 ES Modules,脚本须内联
10渲染差异:系统 WebView 版本不同 → 需跨平台测;这是「小体积」的代价
11sidecar 命名:必须带 -$TARGET_TRIPLE 后缀,否则打包/运行失败
12updatercreateUpdaterArtifacts: true + 签名私钥务必妥存(丢了无法再发更新)

八、权威链接