1 插件开发
9 分钟阅读
本指南面向 Tauri 插件的开发。如果你想要的是当前可用插件列表以及如何使用它们,请访问功能与示例列表。
插件可以挂接到 Tauri 的生命周期、暴露依赖 web view API 的 Rust 代码、用 Rust、Kotlin 或 Swift 代码处理命令,等等。
Tauri 提供了带 web view 功能的窗口系统、在 Rust 进程与 web view 之间发送消息的方式,以及事件系统和若干提升开发体验的工具。按照设计,Tauri 核心不包含并非所有人都需要的功能,而是提供了一种把外部功能加入 Tauri 应用的机制,也就是插件。
一个 Tauri 插件由一个 Cargo crate 和一个可选的 NPM 包组成,后者为其命令和事件提供 API 绑定。此外,插件项目还可以包含一个 Android 库项目和一个用于 iOS 的 Swift 包。你可以在移动端插件开发指南中进一步了解如何为 Android 和 iOS 开发插件。
命名约定
Tauri 插件有一个前缀,后面跟着插件名。插件名在插件配置中的 tauri.conf.json > plugins 下指定。
默认情况下,Tauri 会给你的插件 crate 加上 tauri-plugin- 前缀。这有助于你的插件被 Tauri 社区发现,并能与 Tauri CLI 一起使用。初始化新插件项目时,你必须提供它的名称。生成的 crate 名将是 tauri-plugin-{plugin-name},JavaScript NPM 包名将是 tauri-plugin-{plugin-name}-api(不过我们建议尽可能使用 NPM scope)。Tauri 对 NPM 包的命名约定是 @scope-name/plugin-{plugin-name}。
标识符规则
插件 crate 中的 {plugin-name} 部分,以及能力(capabilities)中引用的任何权限标识符,都必须遵循 Tauri 的标识符语法:
- 小写 ASCII 字母(
a到z)、数字(0到9)和连字符(-)。 - 连字符不能出现在首字符或末字符。
- 只有当标识符使用了前缀时(例如
<plugin-name>:<permission-name>),才允许出现单个冒号(:)。 - 不允许下划线(
_)、大写字母以及其它字符。 - 基础名限制为 64 个字符;带前缀时,完整标识符限制为 129 个字符。
示例:
| 标识符 | 是否有效? |
|---|---|
sqlite | ✓ |
sqlite-store | ✓ |
sqlite-store:allow-read | ✓ |
sqlite_store | ✗(下划线) |
SqliteStore | ✗(大写) |
-sqlite | ✗(前导连字符) |
sqlite- | ✗(末尾连字符) |
sqlite::store | ✗(多个分隔符) |
如果某个插件或权限标识符违反了这些规则,构建会失败并报错 identifiers can only include lowercase ASCII, hyphens which are not leading or trailing, and a single colon if using a prefix。违规值通常是你插件 Cargo.toml 中的插件名,或某个 permissions/*.toml 文件中的权限标识符。
初始化插件项目
要引导创建一个新的插件项目,请运行 plugin new。如果你不需要 NPM 包,请使用 --no-api CLI 标志。如果你想初始化带 Android 和/或 iOS 支持的插件,请使用 --android 和/或 --ios 标志。
安装之后,你可以运行以下命令创建一个插件项目:
包管理器
| |
tauri-plugin-[name] 目录中初始化插件,根据所使用的 CLI 标志,生成的项目结构大致如下:. tauri-plugin-[name]/
├── src/ - Rust 代码
│ ├── commands.rs - 定义 webview 可以使用的命令
| ├── desktop.rs - 桌面端实现
| ├── error.rs - 返回结果中使用的默认错误类型
│ ├── lib.rs - 重新导出合适的实现、设置 state 等
│ ├── mobile.rs - 移动端实现
│ └── models.rs - 共享结构体
├── permissions/ - 存放(生成的)命令权限文件
├── android - Android 库
├── ios - Swift 包
├── guest-js - JavaScript API 绑定的源代码
├── dist-js - 由 guest-js 转译出的产物
├── Cargo.toml - Cargo crate 元数据
└── package.json - NPM 包元数据
如果你已有插件并想为它添加 Android 或 iOS 能力,可以使用 plugin android add 和 plugin ios add 来引导生成移动端库项目,并指导你完成所需的改动。
声明平台支持
插件可以在 crate 的 Cargo.toml 中的 [package.metadata.platforms.support] 一节声明自己支持哪些平台以及支持程度:
| |
每个键是一个平台(windows、linux、macos、android、ios),接受两个字段:
level(必填):如果插件按预期工作则为"full",如果有功能限制则为"partial",如果不支持该平台则为"none"。notes(可选):对注意事项或限制的简短说明。它会以 Markdown 形式渲染在插件页面上。在支持表中,它作为纯文本显示在工具提示里。
功能与示例页面上的支持表和平台过滤器就是由这些元数据生成的。
移动端插件开发
插件可以运行用 Kotlin(或 Java)和 Swift 编写的原生移动端代码。默认插件模板包含一个使用 Kotlin 的 Android 库项目和一个 Swift 包。其中包含一个示例移动端命令,演示如何从 Rust 代码触发它的执行。
更多关于移动端插件开发的内容请阅读移动端插件开发指南。
插件配置
在使用该插件的 Tauri 应用中,插件配置在 tauri.conf.json 中指定,其中 plugin-name 是插件名:
| |
插件的配置设置在 Builder 上,并在运行时解析。下面是使用 Config 结构体指定插件配置的示例:
| |
生命周期事件
插件可以挂接到若干生命周期事件:
- setup:插件正在初始化
- on_navigation:web view 正在尝试进行导航
- on_webview_ready:新窗口正在创建
- on_event:事件循环事件
- on_drop:插件正在被析构
移动端插件还有额外的生命周期事件。
setup
- 时机:插件正在初始化
- 用途:注册移动端插件、管理 state、运行后台任务
| |
on_navigation
- 时机:web view 正在尝试进行导航
- 用途:校验导航或跟踪 URL 变化
返回 false 会取消该导航。
| |
on_webview_ready
- 时机:新窗口已创建
- 用途:为每个窗口执行初始化脚本
| |
on_event
- 时机:事件循环事件
- 用途:处理窗口事件、菜单事件、应用退出请求等核心事件
通过这个生命周期钩子,你可以收到任何事件循环事件的通知。
| |
on_drop
- 时机:插件正在被析构
- 用途:在插件被销毁时执行代码
更多信息见 Drop。
| |
暴露 Rust API
插件在项目 desktop.rs 和 mobile.rs 中定义的 API 会以一个与插件同名(Pascal 命名)的结构体导出给使用者。当插件被 setup 时,会创建该结构体的实例并作为 state 托管,这样使用者就可以在任何时候通过 Manager 实例(例如 AppHandle、App 或 Window)借助插件中定义的扩展 trait 取到它。
例如,global-shortcut 插件定义了一个 GlobalShortcut 结构体,可以通过 GlobalShortcutExt trait 的 global_shortcut 方法读取:
| |
添加命令
命令定义在 commands.rs 文件中。它们就是普通的 Tauri 应用命令,可以直接访问 AppHandle 和 Window 实例、访问 state,并以与应用命令相同的方式接收输入。关于 Tauri 命令的更多细节,请阅读命令指南。
下面这个命令展示了如何通过依赖注入获取 AppHandle 和 Window 实例,并接收两个输入参数(on_progress 和 url):
| |
要把命令暴露给 webview,你必须在 lib.rs 中挂接到 invoke_handler() 调用:
| |
在 webview-src/index.ts 中定义一个绑定函数,让插件使用者可以方便地在 JavaScript 中调用该命令:
| |
测试之前请务必先构建 TypeScript 代码。
命令权限
默认情况下你的命令不能被前端访问。如果你尝试执行其中之一,会收到拒绝错误的 rejection。 要真正暴露命令,你还需要定义允许每个命令的权限。
权限文件
权限以 JSON 或 TOML 文件的形式定义在 permissions 目录中。每个文件都可以定义一组权限、一组权限集以及你插件的默认权限。
权限
权限描述你的插件命令所拥有的特权。它可以允许或拒绝一组命令,并把命令专属作用域和全局作用域关联起来。
| |
作用域
作用域允许你的插件为单个命令定义更深的限制。 每个权限都可以定义一组作用域对象,用来定义对某个命令专属、或对整个插件全局的允许或拒绝内容。
让我们定义一个示例结构体,用来存放 shell 插件被允许启动的二进制文件列表的作用域数据:
| |
命令作用域
你的插件使用者可以在自己的能力(capability)文件中为特定命令定义作用域(见文档)。
你可以用 tauri::ipc::CommandScope 结构体读取命令专属作用域:
| |
全局作用域
当某个权限没有定义任何要允许或拒绝的命令时,它被视为作用域权限,并且只应为你的插件定义全局作用域:
| |
你可以用 tauri::ipc::GlobalScope 结构体读取全局作用域:
| |
为了灵活性,我们建议同时检查全局作用域和命令作用域
Schema
作用域条目需要 schemars 依赖来生成 JSON schema,这样插件使用者才能知道作用域的格式,并在 IDE 中获得自动补全。
要定义 schema,请先把依赖添加到 Cargo.toml 文件:
| |
在你的构建脚本中加入以下代码:
| |
权限集
权限集是单个权限的分组,帮助使用者以更高层次的抽象来管理你的插件。 例如,如果某个 API 使用多个命令,或者一组命令之间存在逻辑关联,你就应当定义一个包含它们的集合:
| |
默认权限
默认权限是标识符为 default 的特殊权限集。建议你默认启用必需的命令。
例如,如果不允许 request 命令,http 插件就毫无用处:
| |
自动生成权限
为每个命令定义权限最简单的方式,是使用插件构建脚本(build.rs 文件)中定义的自动生成选项。
在 COMMANDS 常量中,用 snake_case 定义命令列表(应与命令函数名一致),Tauri 会自动生成 allow-$commandname 和 deny-$commandname 权限。
下面的示例会生成 allow-upload 和 deny-upload 权限:
| |
更多信息请参阅权限概述文档。
管理 State
插件可以用与 Tauri 应用相同的方式管理 state。更多信息请阅读状态管理指南。