7.2 自定义插件开发:Rust crate与JS绑定


官方件不够用时,自己造。本节走完自定义插件的全流程:插件的双端结构、脚手架生成、权限定义、前端绑定、构建发布——并用一个真实的"操作历史记录"插件把每一步落地。读完本节,你能把第 5 章的芯功夫打包成可跨项目复用的标准件,也能读懂官方插件的源码结构。

什么时候值得做成插件

先把判断立住,避免为造轮子而造轮子。三个信号同时出现,再动手:逻辑通用(操作历史、鉴权封装、遥测上报——不是某个业务专属);跨项目复用有明确预期(第二个使用场景已在路上);需要独立权限边界(希望使用方按 6.2 的方式精确授权,而不是把内部命令混进应用命令表)。只占第一条,普通 Rust 模块加命令就够了——插件的额外结构是有成本的。

插件的双端结构

一个插件 = 一个 Rust crate(芯侧容器)+ 一个 npm 包(前端绑定)。脚手架一次生成:

cargo install create-tauri-app --locked # 若未装;也可用官方插件模板工具 cargo tauri plugin new history --directory tauri-plugin-history

生成的目录骨架(节选):

tauri-plugin-history/ ├── src/ │ ├── lib.rs # 插件入口:Builder 与注册 │ ├── commands.rs # 命令实现 │ └── error.rs # 插件错误类型 ├── permissions/ # 权限定义:默认集与具体权限 │ └── default.toml ├── guest-js/ # 前端绑定源码(构建时编译进 npm 包) │ └── index.ts ├── Cargo.toml └── package.json

这个结构本身就是教材:permissions 目录揭示了权限体系的底层——权限不是配置里的字符串魔法,而是插件自己声明的一组标识与约束;guest-js 揭示了官方 npm 包的本质——只是对 invoke 的一层封装。

芯侧:容器与命令

写一个记录操作历史的插件,芯侧核心:

// lib.rs use tauri::{ plugin::{Builder, TauriPlugin}, Manager, Runtime, }; mod commands; mod state; pub fn init<R: Runtime>() -> TauriPlugin<R> { Builder::new("history") .setup(|app, _api| { app.manage(state::HistoryStore::new(100)); // 容量上限一百条 Ok(()) }) .invoke_handler(tauri::generate_handler![ commands::record, commands::list_recent, commands::undo_last ]) .build() }
// commands.rs use tauri::{State, AppHandle}; use crate::state::HistoryStore; #[tauri::command] pub fn record(state: State<'_, HistoryStore>, action: String) -> Result<(), String> { state.push(action); Ok(()) } #[tauri::command] pub fn list_recent(state: State<'_, HistoryStore>, limit: u32) -> Result<Vec<String>, String> { Ok(state.recent(limit.clamp(1, 100) as usize)) }

与第 5 章写应用命令几乎一致——插件命令就是命令,只是住在插件容器里、以插件名为前缀暴露(history 命名空间)。Host 应用接入即 7.1 的四动作:cargo add 本地路径依赖、Builder 挂 tauri_plugin_history::init()

权限定义:给插件发卡的规则

permissions 目录里的 default.toml 声明默认权限集:

# permissions/default.toml "$schema" = "schemas/schema.json" [default] description = "历史记录插件的基础读写权限" permissions = ["allow-record", "allow-list-recent"]

使用方在 Capabilities 里写 history:default 就拿到默认集,需要更细就单授 history:allow-undo-last。设计权限集的原则沿用 6.1:默认集给只读与低危操作,写操作单列权限——undo 这类改状态的操作不进默认集,使用方显式授权才生效。

前端绑定:guest-js 的封装套路

// guest-js/index.ts import { invoke } from '@tauri-apps/api/core'; export async function record(action: string): Promise<void> { await invoke('plugin:history|record', { action }); } export async function listRecent(limit: number): Promise<string[]> { return await invoke('plugin:history|list_recent', { limit }); }

注意命令名的完整形态:插件名|命令名。绑定包只做参数命名与类型封装——使用方拿到的是带类型的函数,不是裸命令字符串。构建工具链会把 guest-js 编译进 npm 包,发布时 Rust crate 发 crates 源、npm 包发 npm 源,版本号保持同步(与 7.1 的版本对齐纪律一致)。

插件化改造的迁移路径

把现有代码升级成插件的顺序:先抽 Rust 模块(纯函数与状态类型搬进 crate,应用命令改为调模块);再挪命令(命令搬进插件容器,应用侧改走插件);后补前端绑定(bridge 里对应函数换成绑定包导出);最后定义权限(默认集加单列权限,Capabilities 更新发卡)。每步独立可回退,应用全程可构建——插件化是搬运不是重写。

本节要点回顾

  • 三个信号再插件化:逻辑通用、复用在途、需要独立权限边界;
  • 双端结构:Rust 容器加 npm 绑定,permissions 目录揭示权限的声明本质;
  • 命令前缀:插件命令以插件名为命名空间,前端写 plugin 名竖线命令名;
  • 默认集收低危:写操作单列权限,使用方显式授权;
  • 迁移四步:抽模块、挪命令、补绑定、定权限,每步可回退。

标准件会造了。下一节装三件深集成:托盘、通知与全局快捷键——桌面应用的存在感从这三件来。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U