人人都会AI编程

17.4 自定义插件开发

更新时间:2026-07-11

在 Tauri 中,插件是扩展应用能力的标准方式。除了使用社区提供的插件(如 fsdialogshell 等),当你有特定的需求无法被现有插件满足时,就可以开发自定义插件。这个过程比你想象的要简单——本质上就是把 Rust 功能封装成一个可复用的包,并暴露给前端。


1. 插件结构快览

一个典型的 Tauri 插件通常包含两个部分:

  • Rust 端:一个标准的 Rust crate,实现具体功能、定义命令、声明权限。
  • 前端端:一个 npm 包,提供 TypeScript 封装,让前端能舒适地调用插件命令,并带有类型提示。

在 Tauri v2 中,插件通过权限系统(Permissions)明确定义哪些命令可以被调用,这进一步强化了安全模型。


2. 快速上手:编写一个计算器插件

假设我们想封装一个安全的数学计算功能,让前端可以调用 adddivide 命令。

2.1 用脚手架创建插件项目

Tauri CLI 可以帮我们生成插件模板:

npm create tauri-plugin@latest

按提示选择插件名(如 tauri-plugin-calc)、是否包含前端 npm 包等。这会生成一个结构类似如下的目录:

tauri-plugin-calc/
├── Cargo.toml          # Rust 依赖与元信息
├── src/
│   └── lib.rs          # 插件逻辑
├── guest-js/
│   └── index.ts        # 前端封装
├── permissions/        # 权限定义
│   └── default.toml
└── package.json        # 前端包信息

2.2 编写 Rust 命令

lib.rs 中,我们定义两个命令并注册插件:

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

#[tauri::command]
fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[tauri::command]
fn divide(a: i32, b: i32) -> Result<f64, String> {
    if b == 0 {
        Err("除数不能为零".into())
    } else {
        Ok(a as f64 / b as f64)
    }
}

pub fn init() -> TauriPlugin<()> {
    Builder::new("calc")
        .invoke_handler(tauri::generate_handler![add, divide])
        .build()
}

这里的 adddivide 就是可被前端调用的命令,divide 还展示了错误处理。

2.3 声明权限

permissions/default.toml 中,我们需要允许调用这两个命令:

# permissions/default.toml
[default]
description = "启用计算器插件的基础功能"
commands = ["add", "divide"]
scope = {}

若将来需要更细粒度的控制(比如只允许加法),可以定义额外的权限集。

2.4 编写前端封装

guest-js/index.ts 中,我们用 Tauri 的 invoke 包装命令,并暴露给用户:

import { invoke } from '@tauri-apps/api/core';

export async function add(a: number, b: number): Promise<number> {
  return await invoke('plugin:calc|add', { a, b });
}

export async function divide(a: number, b: number): Promise<number> {
  return await invoke('plugin:calc|divide', { a, b });
}

注意命令前缀 plugin:calc|,这是 Tauri v2 插件调用的格式,用于隔离不同插件的命名空间。


3. 在主应用中集成插件

使用这个插件只需要两步。

3.1 安装后端插件

在主 Tauri 项目的 src-tauri/Cargo.toml 中添加依赖:

[dependencies]
tauri-plugin-calc = { path = "../tauri-plugin-calc" }  # 或发布后使用版本号

然后在 src-tauri/src/main.rs 中注册:

fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_calc::init())
        .run(tauri::generate_context!())
        .expect("启动失败");
}

3.2 安装前端包

如果想把 TypeScript 封装也一起用,可以在主应用的项目中安装前端包(假设已发布到 npm 或本地 file:):

npm add tauri-plugin-calc

并在使用位置直接调用:

import { add } from 'tauri-plugin-calc';
const result = await add(1, 2);

3.3 启用权限

在主应用的 src-tauri/capabilities/ 目录下,为插件添加权限声明。如果插件提供了 default.toml,可以直接引用:

// src-tauri/capabilities/calc.json
{
  "identifier": "calc-capability",
  "windows": ["main"],
  "permissions": [
    "calc:default"
  ]
}

现在,前端调用 adddivide 就不会被权限系统拦截了。


4. 进阶技巧

  • 传递状态:插件可以持有自己的结构化状态(数据库连接、设备句柄等),通过 Builder::setup(|app, _api| {...}) 在应用启动时初始化。
  • 前端到后端的流式传输:使用 tauri::ipc::Channel 可以让 Rust 命令返回一个流,前端通过 onmessage 监听实时数据。
  • 条件编译:若插件功能只在特定平台有效,可以用 #[cfg(target_os = "windows")] 限制。
  • 分发与发布:将插件发布到 crates.io(Rust 端)和 npm(前端)后,其他开发者就能直接集成,享受类型安全和开箱即用的体验。

自定义插件把“一次编写,到处复用”的理念带到了 Tauri 生态中。当你发现自己需要在多个 Tauri 项目中重复相同的基础功能时,抽出 30 分钟将它做成一个插件,会是回报最高的决策之一。