插件开发 #

一、插件概述 #

1.1 什么是插件 #

Tauri 插件是扩展应用功能的模块化组件,可以添加新的 API、命令和功能。

text
┌─────────────────────────────────────────────────────────────┐
│                      插件架构                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                    Tauri 应用                        │   │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐│   │
│  │  │  插件 A     │  │  插件 B     │  │  插件 C     ││   │
│  │  │  fs         │  │  dialog     │  │  shell      ││   │
│  │  └─────────────┘  └─────────────┘  └─────────────┘│   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 插件类型 #

类型 说明
官方插件 Tauri 团队维护
社区插件 社区开发者贡献
自定义插件 自己开发的插件

二、创建插件 #

2.1 使用脚手架 #

bash
# 创建插件项目
cargo tauri plugin new my-plugin

# 或使用 pnpm
pnpm tauri plugin new my-plugin

2.2 插件结构 #

text
my-plugin/
├── src/
│   ├── lib.rs           # 插件主入口
│   └── commands.rs      # 命令定义
├── Cargo.toml           # Rust 配置
├── permissions/
│   ├── default.toml     # 默认权限
│   └── allow-*.toml     # 允许权限
├── guest-js/
│   ├── index.ts         # 前端 API
│   └── package.json     # 前端配置
└── README.md

2.3 插件主入口 #

rust
// src/lib.rs
use tauri::plugin::{Builder, TauriPlugin};
use tauri::Runtime;

mod commands;

pub fn init<R: Runtime>() -> TauriPlugin<R> {
    Builder::new("my-plugin")
        .invoke_handler(tauri::generate_handler![
            commands::my_command,
        ])
        .build()
}

2.4 定义命令 #

rust
// src/commands.rs
use tauri::command;

#[command]
pub async fn my_command(param: String) -> Result<String, String> {
    Ok(format!("Received: {}", param))
}

三、前端 API #

3.1 创建前端模块 #

typescript
// guest-js/index.ts
import { invoke } from '@tauri-apps/api/core';

export async function myFunction(param: string): Promise<string> {
    return invoke('my_command', { param });
}

export interface MyPluginOptions {
    option1: boolean;
    option2: string;
}

3.2 导出模块 #

json
// guest-js/package.json
{
    "name": "tauri-plugin-my-plugin",
    "version": "1.0.0",
    "main": "index.ts",
    "types": "index.ts",
    "exports": {
        ".": "./index.ts"
    }
}

四、权限配置 #

4.1 定义权限 #

toml
# permissions/default.toml
[default]
description = "Default permissions for my-plugin"
permissions = ["allow-my-command"]
toml
# permissions/allow-my-command.toml
[[permission]]
identifier = "allow-my-command"
description = "Allow my-command"
commands.allow = ["my_command"]

4.2 权限检查 #

rust
use tauri::command;

#[command]
pub async fn protected_command(app: tauri::AppHandle) -> Result<String, String> {
    if !app.has_permission("my-plugin:allow-protected") {
        return Err("Permission denied".to_string());
    }
    
    Ok("Protected operation completed".to_string())
}

五、插件状态 #

5.1 定义状态 #

rust
use std::sync::Mutex;

pub struct PluginState {
    data: Mutex<Vec<String>>,
}

impl Default for PluginState {
    fn default() -> Self {
        Self {
            data: Mutex::new(Vec::new()),
        }
    }
}

5.2 注册状态 #

rust
use tauri::plugin::{Builder, TauriPlugin};
use tauri::Runtime;

pub fn init<R: Runtime>() -> TauriPlugin<R> {
    Builder::new("my-plugin")
        .invoke_handler(tauri::generate_handler![
            commands::add_data,
            commands::get_data,
        ])
        .setup(|app, _api| {
            app.manage(PluginState::default());
            Ok(())
        })
        .build()
}

5.3 使用状态 #

rust
use tauri::command;
use tauri::State;

#[command]
pub fn add_data(state: State<PluginState>, item: String) {
    state.data.lock().unwrap().push(item);
}

#[command]
pub fn get_data(state: State<PluginState>) -> Vec<String> {
    state.data.lock().unwrap().clone()
}

六、插件事件 #

6.1 发送事件 #

rust
use tauri::{command, Emitter};

#[command]
pub async fn trigger_event(app: tauri::AppHandle) -> Result<(), String> {
    app.emit("my-plugin:event", { "data": "value" })
        .map_err(|e| e.to_string())
}

6.2 前端监听 #

typescript
import { listen } from '@tauri-apps/api/event';

await listen('my-plugin:event', (event) => {
    console.log('Event received:', event.payload);
});

七、插件配置 #

7.1 定义配置 #

rust
use serde::Deserialize;

#[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PluginConfig {
    pub enabled: bool,
    pub option1: String,
    pub option2: i32,
}

7.2 读取配置 #

rust
use tauri::plugin::{Builder, TauriPlugin};
use tauri::Runtime;

pub fn init<R: Runtime>() -> TauriPlugin<R> {
    Builder::new("my-plugin")
        .setup(|app, _api| {
            let config = app.config()
                .plugins
                .get("my-plugin")
                .and_then(|v| serde_json::from_value(v.clone()).ok())
                .unwrap_or_default();
            
            app.manage(config);
            Ok(())
        })
        .build()
}

7.3 配置示例 #

json
// tauri.conf.json
{
    "plugins": {
        "my-plugin": {
            "enabled": true,
            "option1": "value",
            "option2": 42
        }
    }
}

八、发布插件 #

8.1 发布到 crates.io #

toml
# Cargo.toml
[package]
name = "tauri-plugin-my-plugin"
version = "1.0.0"
edition = "2021"
description = "My Tauri plugin"
license = "MIT"
repository = "https://github.com/user/tauri-plugin-my-plugin"
bash
# 发布
cargo publish

8.2 发布到 npm #

bash
# 构建
cd guest-js
pnpm build

# 发布
pnpm publish

九、最佳实践 #

9.1 命名规范 #

text
插件名称: my-plugin
Rust crate: tauri-plugin-my-plugin
npm 包: tauri-plugin-my-plugin

9.2 文档 #

markdown
# My Plugin

## Installation

\`\`\`bash
pnpm add tauri-plugin-my-plugin
\`\`\`

## Usage

\`\`\`typescript
import { myFunction } from 'tauri-plugin-my-plugin';

const result = await myFunction('param');
\`\`\`

## API

### myFunction(param: string): Promise<string>

Description of the function.

9.3 错误处理 #

rust
use thiserror::Error;

#[derive(Debug, Error)]
pub enum PluginError {
    #[error("Invalid parameter: {0}")]
    InvalidParameter(String),
    
    #[error("Operation failed: {0}")]
    OperationFailed(String),
}

impl From<PluginError> for String {
    fn from(error: PluginError) -> String {
        error.to_string()
    }
}

十、总结 #

10.1 核心要点 #

要点 说明
插件结构 lib.rs + commands.rs
前端 API TypeScript 封装
权限配置 TOML 文件定义
状态管理 使用 app.manage
事件系统 发送和监听事件

10.2 下一步 #

现在你已经掌握了插件开发,接下来让我们学习 原生模块,了解如何开发 Rust 原生模块!

最后更新:2026-03-28