mcpField
T
tauri-v2

tauri-v2

github.com/robinebers开发4.5k43 次安装今天更新
代码仓库

关于 tauri-v2

tauri-v2 是面向开发者的 Tauri v2 开发技能,用于构建采用 Web 前端和 Rust 后端的桌面及移动应用。它提供命令、权限、状态管理、IPC 与构建问题的实现模式和排查指引。

主要功能

  1. 01Tauri v2 命令与 IPC 模式
  2. 02能力与权限配置
  3. 03Rust 状态管理和错误处理
  4. 04事件发送与通道流式传输
  5. 05构建配置与故障排查

适用场景

  1. 01注册由前端调用的 Rust 命令
  2. 02排查权限或 IPC 故障
  3. 03准备 Tauri 应用的移动端构建

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/robinebers/openusage --skill tauri-v2

安装后在 Claude Code 中输入/tauri-v2确认已加载。

附带文件references/capabilities-reference.mdreferences/ipc-patterns.md

详细介绍

Tauri v2 开发技能

使用 Web 前端和 Rust 后端构建跨平台桌面和移动应用。

开始之前

此技能可避免 8 个以上的常见错误,并节省约 60% 的 Token。

指标不使用技能使用技能
设置时间约 2 小时约 30 分钟
常见错误8 个以上0
Token 用量高(探索)低(直接使用模式)
此技能可避免的已知问题
  1. 因缺少 capabilities 导致权限被拒绝
  2. 因 generate_handler! 中未注册命令导致 IPC 失败
  3. 类型不匹配导致状态管理崩溃
  4. 因缺少 Rust target 导致移动端构建失败
  5. dev URL 配置错误导致白屏

快速开始

第 1 步:创建 Tauri 命令
// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: String) -> String {
    format!("Hello, {}!", name)
}

pub fn run() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

为何重要: 未添加到 generate_handler![] 的命令从前端调用时会静默失败。

第 2 步:从前端调用
import { invoke } from '@tauri-apps/api/core';

const greeting = await invoke<string>('greet', { name: 'World' });
console.log(greeting); // "Hello, World!"

为何重要: 使用 @tauri-apps/api/core(不要使用 @tauri-apps/api/tauri,后者是 v1 API)。

第 3 步:添加所需权限
// src-tauri/capabilities/default.json
{
    "$schema": "../gen/schemas/desktop-schema.json",
    "identifier": "default",
    "windows": ["main"],
    "permissions": ["core:default"]
}

为何重要: Tauri v2 默认拒绝所有操作,所有操作都需要显式授予权限。

关键规则

始终遵循
  • 在 tauri::generate_handler![cmd1, cmd2, ...] 中注册每个命令
  • 命令返回 Result<T, E>,以便正确处理错误
  • 使用 Mutex<T> 管理多个命令访问的共享状态
  • 使用任何插件功能前先添加 capabilities
  • 使用 lib.rs 存放共享代码(移动端构建所必需)
绝不
  • 绝不要在异步命令中使用借用类型(&str),应使用拥有所有权的类型
  • 绝不要阻塞主线程;I/O 操作应使用异步方式
  • 绝不要硬编码路径;应使用 Tauri 路径 API(app.path())
  • 绝不要跳过 capability 设置;即使是“安全”的操作也需要权限
常见错误

错误——在异步命令中使用借用类型:

#[tauri::command]
async fn bad(name: &str) -> String { // Compile error!
    name.to_string()
}

正确——使用拥有所有权的类型:

#[tauri::command]
async fn good(name: String) -> String {
    name
}

原因: 异步命令无法在 await 点之间借用数据;Tauri 要求异步命令参数使用拥有所有权的类型。

预防已知问题

问题根本原因解决方案
“Command not found”未添加到 generate_handler!将命令添加到 handler 宏中
“Permission denied”缺少 capability添加到 capabilities/default.json
访问状态时崩溃State<T> 中类型不匹配使用与 .manage() 完全一致的类型
启动时白屏前端未能构建检查配置中的 beforeDevCommand
IPC 超时异步命令阻塞移除阻塞代码或使用 spawn
移动端构建失败缺少 Rust target运行 rustup target add <target>

配置参考

tauri.conf.json
{
    "$schema": "./gen/schemas/desktop-schema.json",
    "productName": "my-app",
    "version": "1.0.0",
    "identifier": "com.example.myapp",
    "build": {
        "devUrl": "http://localhost:5173",
        "frontendDist": "../dist",
        "beforeDevCommand": "npm run dev",
        "beforeBuildCommand": "npm run build"
    },
    "app": {
        "windows": [{
            "label": "main",
            "title": "My App",
            "width": 800,
            "height": 600
        }],
        "security": {
            "csp": "default-src 'self'; img-src 'self' data:",
            "capabilities": ["default"]
        }
    },
    "bundle": {
        "active": true,
        "targets": "all",
        "icon": ["icons/icon.icns", "icons/icon.ico", "icons/icon.png"]
    }
}

关键设置:

  • build.devUrl:必须与前端开发服务器端口一致
  • app.security.capabilities:capability 文件标识符数组
Cargo.toml
[package]
name = "app"
version = "0.1.0"
edition = "2021"

[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]

[build-dependencies]
tauri-build = { version = "2", features = [] }

[dependencies]
tauri = { version = "2", features = [] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

关键设置:

  • [lib] 部分:移动端构建所必需
  • crate-type:跨平台构建必须包含全部三种类型

常见模式

错误处理模式
use thiserror::Error;

#[derive(Debug, Error)]
enum AppError {
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    #[error("Not found: {0}")]
    NotFound(String),
}

impl serde::Serialize for AppError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: serde::ser::Serializer {
        serializer.serialize_str(self.to_string().as_ref())
    }
}

#[tauri::command]
fn risky_operation() -> Result<String, AppError> {
    Ok("success".into())
}
状态管理模式
use std::sync::Mutex;
use tauri::State;

struct AppState {
    counter: u32,
}

#[tauri::command]
fn increment(state: State<'_, Mutex<AppState>>) -> u32 {
    let mut s = state.lock().unwrap();
    s.counter += 1;
    s.counter
}

// In builder:
tauri::Builder::default()
    .manage(Mutex::new(AppState { counter: 0 }))
事件发送模式
use tauri::Emitter;

#[tauri::command]
fn start_task(app: tauri::AppHandle) {
    std::thread::spawn(move || {
        app.emit("task-progress", 50).unwrap();
        app.emit("task-complete", "done").unwrap();
    });
}
import { listen } from '@tauri-apps/api/event';

const unlisten = await listen('task-progress', (e) => {
    console.log('Progress:', e.payload);
});
// Call unlisten() when done
Channel 流式传输模式
use tauri::ipc::Channel;

#[derive(Clone, serde::Serialize)]
#[serde(tag = "event", content = "data")]
enum DownloadEvent {
    Progress { percent: u32 },
    Complete { path: String },
}

#[tauri::command]
async fn download(url: String, on_event: Channel<DownloadEvent>) {
    for i in 0..=100 {
        on_event.send(DownloadEvent::Progress { percent: i }).unwrap();
    }
    on_event.send(DownloadEvent::Complete { path: "/downloads/file".into() }).unwrap();
}
import { invoke, Channel } from '@tauri-apps/api/core';

const channel = new Channel<DownloadEvent>();
channel.onmessage = (msg) => console.log(msg.event, msg.data);
await invoke('download', { url: 'https://...', onEvent: channel });

捆绑资源

参考资料

位于 references/ 中:

注意: 如需深入了解特定主题,请参阅上面的参考文件。

依赖项

必需
包版本用途
@tauri-apps/cli^2.0.0CLI 工具
@tauri-apps/api^2.0.0前端 API
tauri^2.0.0Rust 核心
tauri-build^2.0.0构建脚本
可选(插件)
包版本用途
tauri-plugin-fs^2.0.0文件系统访问
tauri-plugin-dialog^2.0.0原生对话框
tauri-plugin-shell^2.0.0Shell 命令、打开 URL
tauri-plugin-http^2.0.0HTTP 客户端
tauri-plugin-store^2.0.0键值存储

官方文档

故障排除

启动时出现白屏

**症状:**应用启动,但显示空白屏幕

解决方案:

  1. 确认 devUrl 与前端开发服务器端口一致
  2. 检查 beforeDevCommand 是否运行了开发服务器
  3. 打开 DevTools(Cmd+Option+I / Ctrl+Shift+I)检查错误
命令返回 Undefined

症状:invoke() 返回 undefined,而不是预期值

解决方案:

  1. 确认命令已添加到 generate_handler![]
  2. 检查 Rust 命令是否实际返回了值
  3. 确保参数名称匹配(JS 中默认使用 camelCase,Rust 中默认使用 snake_case)
移动端构建失败

**症状:**Android/iOS 构建因缺少目标平台而失败

解决方案:

# Android targets
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android

# iOS targets (macOS only)
rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim

设置检查清单

使用此技能前,请确认:

  • npx tauri info 显示正确的 Tauri v2 版本
  • src-tauri/capabilities/default.json 存在,且至少包含 core:default
  • 所有命令均已在 generate_handler![] 中注册
  • lib.rs 包含共享代码(用于移动端支持)
  • 已为目标平台安装所需的 Rust 目标

评论

支持 Markdown