Tauri(十八)——如何开发 Tauri 插件

前言

Tauri 项目也做了一段时间了,也有用别人开发的插件。自己也想知道如何开发 Tauri 插件。

Tauri 插件介绍

插件可以挂载到 Tauri 的生命周期中暴露需求 webview API 的 Rust 代码,使用 Rust、Kotlin 或 Swift 代码处理命令并能处理更多需求。

Tauri 提供了一个基于 webview 功能的视窗系统,一个在 Rust 进程和 webview 之间发送信息的方式,一个事件系统,以及一些增强开发体验的工具。 设计上 Tauri Core 只包含所有人都需要的功能。相对地,它提供了一种将外部功能添加到 Tauri 应用程序中的机制,被称为插件。

一个 Tauri 插件由一个 Cargo 包和一个可选的 NPM 包(用于提供命令和事件 API 绑定)构成

何时需要开发 Tauri 插件?

  1. 需要访问系统原生 API(文件、硬件、网络底层)
  2. 性能关键型任务(大数据处理、实时计算)
  3. 代码复用与团队协作(跨项目共享功能模块)
  4. 安全敏感场景(加密、认证、许可证管理)

通过 Tauri 插件,开发者可以 兼顾 Web 的开发效率与 Native 的性能能力,构建真正高性能、跨平台的桌面应用。

Tauri 插件核心概念

插件作用:封装可复用的跨平台功能模块(如硬件访问、加密算法),通过 Rust 后端 + 前端 API 暴露能力。

技术栈

  • Rust:核心逻辑实现
  • TypeScript/JavaScript:前端 API 接口
  • WASM(可选):浏览器端直接调用

创建基础插件模板

1. 命名规范

Tauri 插件具有一个前缀(Rust 包使用 tauri-plugin- 前缀,NPM 包使用 @tauri-apps/plugin- 前缀),随后是插件名称。 插件名称由插件配置中的 tauri.conf.json > plugin 和许可列表中的配置确定。

默认情况下,Tauri 会在你的插件 crate 前面加上 tauri-plugin-。这有助于你的插件被 Tauri 社区发现,但不是必须的。初始化新插件项目时,必须提供其名称。生成包名称将为 tauri-plugin-{plugin-name},JavaScript NPM 包名称为 tauri-plugin-{plugin-name}-api(尽管我们建议使用 NPM 范围如果可能的话)。NPM 包的 Tauri 命名约定是 @scope-name/plugin-{plugin-name}

2. 初始化 Rust 插件库

使用引导创建一个新的插件项目,请运行 plugin new。如果不需要相应的 NPM 程序包,请使用 --no-api 命令行标志。

bash 复制代码
pnpm tauri plugin new [name]

cargo new tauri-plugin-example --lib
cd tauri-plugin-example

这会在 tauri-plugin-[name] 目录下初始化插件,取决于初始化插件时所选择的命令行标志,项目将具有以下结构:

css 复制代码
. tauri-plugin-[name]/
├── src/                - Rust 代码
│ ├── commands.rs       - 定义 webview 可用的命令
| ├── desktop.rs        - 桌面实现
| ├── error.rs          - 用于返回 results 的默认的错误类型
│ ├── lib.rs            - 重新导出适当的实现、设置状态......
│ ├── mobile.rs         - 移动端实现
│ └── models.rs         - 公共的结构体
├── permissions/        - 这将托管(生成的)命令的权限文件
├── android             - 安卓库
├── ios                 - Swift 包
├── guest-js            - JavaScript API 绑定的源代码
├── dist-js             - 从 guest-js 转译的资源
├── Cargo.toml          - Cargo 包元数据
└── package.json        - NPM 包元数据

3. 编辑 Cargo.toml

toml 复制代码
[package]
name = "tauri-plugin-example"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]  # 编译为动态库

[dependencies]
tauri = { version = "2.0", features = ["plugin"] }
serde = { version = "1.0", features = ["derive"] }  # 序列化支持

4. 实现插件结构

rust 复制代码
// src/lib.rs
use tauri::{
  plugin::{Builder, TauriPlugin},
  Runtime, AppHandle,
};

// 定义插件配置(可选)
#[derive(serde::Deserialize)]
pub struct Config {
  api_key: String,
}

// 核心插件实现
pub fn init<R: Runtime>() -> TauriPlugin<R, Config> {
  Builder::new("example")
    .setup(|app, config| {
      println!("插件初始化,配置密钥: {}", config.api_key);
      Ok(())
    })
    .invoke_handler(|app, invoke| {
      // 处理前端调用
    })
    .build()
}

5. 生命周期事件

插件可以挂载到如下生命周期事件中:

实现前后端通信

1. 定义 Rust 命令

rust 复制代码
// 添加命令处理
#[tauri::command]
fn greet(name: &str) -> String {
  format!("Hello, {}!", name)
}

// 更新插件初始化
pub fn init<R: Runtime>() -> TauriPlugin<R, Config> {
  Builder::new("example")
    .setup(|app, config| { /* ... */ })
    .invoke_handler(tauri::generate_handler![greet])  // 注册命令
    .build()
}

2. 前端调用插件

typescript 复制代码
// 前端集成 (JavaScript/TypeScript)
import { invoke } from "@tauri-apps/api";

async function callPlugin() {
  const response = await invoke("plugin:example|greet", { name: "World" });
  console.log(response); // 输出 "Hello, World!"
}

高级功能扩展

1. 事件系统

rust 复制代码
// Rust 端触发事件
app.emit_all("plugin-event", "数据载荷").unwrap();

// 前端监听
import { listen } from "@tauri-apps/api/event";
listen("plugin-event", (event) => {
  console.log("收到事件:", event.payload);
});

2. 状态管理

rust 复制代码
// 定义共享状态
struct AppState {
  counter: Mutex<i32>,
}

// 注册状态
app.manage(AppState { counter: Mutex::new(0) });

// 在命令中使用状态
#[tauri::command]
fn increment(state: State<AppState>) -> i32 {
  let mut counter = state.counter.lock().unwrap();
  *counter += 1;
  *counter
}

插件集成到 Tauri 应用

1. 本地插件引用

toml 复制代码
# 主应用 Cargo.toml
[dependencies]
tauri-plugin-example = { path = "../tauri-plugin-example" }

2. 初始化插件

rust 复制代码
// main.rs
fn main() {
  tauri::Builder::default()
    .plugin(tauri_plugin_example::init())
    .run(tauri::generate_context!())
    .expect("运行失败");
}

发布插件

1. 打包发布到 crates.io

bash 复制代码
cargo publish --allow-dirty

2. 前端用户安装

bash 复制代码
npm install tauri-plugin-example

调试技巧

  1. Rust 日志输出

    rust 复制代码
    log::info!("调试信息: {:?}", data);

    启动应用时加环境变量:

    bash 复制代码
    RUST_LOG=info cargo tauri dev
  2. 前端 DevTools

    rust 复制代码
    .setup(|app| {
      #[cfg(debug_assertions)]
      app.get_window("main").unwrap().open_devtools();
      Ok(())
    })

相关插件

  1. github.com/tauri-apps/...
  2. v2.tauri.app/zh-cn/plugi...
  3. v2.tauri.app/zh-cn/devel...
相关推荐
小墨宝1 小时前
js 生成pdf 并上传文件
前端·javascript·pdf
HED1 小时前
用扣子快速手撸人生中第一个AI智能应用!
前端·人工智能
DN金猿1 小时前
使用npm install或cnpm install报错解决
前端·npm·node.js
丘山子1 小时前
一些鲜为人知的 IP 地址怪异写法
前端·后端·tcp/ip
志存高远662 小时前
Kotlin 的 suspend 关键字
前端
www_pp_2 小时前
# 构建词汇表:自然语言处理中的关键步骤
前端·javascript·自然语言处理·easyui
天天扭码2 小时前
总所周知,JavaScript中有很多函数定义方式,如何“因地制宜”?(ˉ﹃ˉ)
前端·javascript·面试
一个专注写代码的程序媛2 小时前
为什么vue的key值,不用index?
前端·javascript·vue.js
장숙혜3 小时前
ElementUi的Dropdown下拉菜单的详细介绍及使用
前端·javascript·vue.js
火柴盒zhang3 小时前
websheet之 编辑器
开发语言·前端·javascript·编辑器·spreadsheet·websheet