跳到內容
Tauri

外掛程式開發

外掛程式能夠掛鉤到 Tauri 生命週期、公開依賴於 Web 視圖 API 的 Rust 程式碼、使用 Rust、Kotlin 或 Swift 程式碼處理命令等等。

Tauri 提供具有 Web 視圖功能的視窗系統、一種在 Rust 進程和 Web 視圖之間發送訊息的方式,以及一個事件系統以及多種工具來增強開發體驗。 根據設計,Tauri 核心不包含並非所有人需要的功能。相反,它提供了一種機制,可將外部功能添加到名為外掛程式的 Tauri 應用程式中。

Tauri 外掛程式由 Cargo 程式碼箱和一個可選的 NPM 套件組成,該套件為其命令和事件提供 API 綁定。 此外,外掛程式專案可以包含一個 Android 程式庫專案和一個用於 iOS 的 Swift 套件。您可以在行動外掛程式開發指南中了解有關開發 Android 和 iOS 外掛程式的更多資訊。

命名慣例

Tauri 外掛程式具有前綴,後跟外掛程式名稱。 外掛程式名稱在 tauri.conf.json > plugins 下的外掛程式配置中指定。

預設情況下,Tauri 會以外掛程式程式碼箱加上前綴 tauri-plugin-。 這有助於您的外掛程式被 Tauri 社群發現,並與 Tauri CLI 一起使用。 初始化新的外掛程式專案時,您必須提供其名稱。產生的程式碼箱名稱將為 tauri-plugin-{plugin-name},而 JavaScript NPM 套件名稱將為 tauri-plugin-{plugin-name}-api(儘管我們建議盡可能使用 NPM 作用域)。 NPM 套件的 Tauri 命名慣例為 @scope-name/plugin-{plugin-name}

初始化外掛程式專案

若要引導新的外掛程式專案,請執行 plugin new。 如果您不需要 NPM 套件,請使用 --no-api CLI 標誌。 如果您想要使用 Android 和/或 iOS 支援初始化外掛程式,請使用 --android 和/或 --ios 標誌。

安裝後,您可以執行以下命令來建立外掛程式專案

npx @tauri-apps/cli plugin new [name]

這將在外掛程式目錄 tauri-plugin-[name] 中初始化外掛程式,並且根據使用的 CLI 標誌,產生的專案將如下所示

. tauri-plugin-[name]/
├── src/ - Rust code
│ ├── commands.rs - Defines the commands the webview can use
| ├── desktop.rs - Desktop implementation
| ├── error.rs - Default error type to use in returned results
│ ├── lib.rs - Re-exports appropriate implementation, setup state...
│ ├── mobile.rs - Mobile implementation
│ └── models.rs - Shared structs
├── permissions/ - This will host (generated) permission files for commands
├── android - Android library
├── ios - Swift package
├── guest-js - Source code of the JavaScript API bindings
├── dist-js - Transpiled assets from guest-js
├── Cargo.toml - Cargo crate metadata
└── package.json - NPM package metadata

如果您有現有的外掛程式,並且想要為其新增 Android 或 iOS 功能,則可以使用 plugin android addplugin ios add 來引導行動程式庫專案,並引導您完成所需的變更。

行動外掛程式開發

外掛程式可以執行以 Kotlin(或 Java)和 Swift 撰寫的原生行動程式碼。 預設外掛程式範本包含一個使用 Kotlin 的 Android 程式庫專案和一個 Swift 套件。 它包含一個範例行動命令,示範如何從 Rust 程式碼觸發其執行。

請在行動外掛程式開發指南中閱讀更多關於開發行動裝置外掛程式的資訊。

外掛程式配置

在使用外掛程式的 Tauri 應用程式中,外掛程式配置在 tauri.conf.json 中指定,其中 plugin-name 是外掛程式的名稱

{
"build": { ... },
"tauri": { ... },
"plugins": {
"plugin-name": {
"timeout": 30
}
}
}

外掛程式的配置設定在 Builder 上,並在執行階段進行解析。 以下是使用 Config 結構指定外掛程式配置的範例

src/lib.rs
use tauri::plugin::{Builder, Runtime, TauriPlugin};
use serde::Deserialize;
// Define the plugin config
#[derive(Deserialize)]
struct Config {
timeout: usize,
}
pub fn init<R: Runtime>() -> TauriPlugin<R, Config> {
// Make the plugin config optional
// by using `Builder::<R, Option<Config>>` instead
Builder::<R, Config>::new("<plugin-name>")
.setup(|app, api| {
let timeout = api.config().timeout;
Ok(())
})
.build()
}

生命週期事件

外掛程式可以掛鉤到多個生命週期事件

行動外掛程式還有其他生命週期事件

setup

  • 何時:正在初始化外掛程式
  • 原因:註冊行動外掛程式、管理狀態、執行背景工作
src/lib.rs
use tauri::{Manager, plugin::Builder};
use std::{collections::HashMap, sync::Mutex, time::Duration};
struct DummyStore(Mutex<HashMap<String, String>>);
Builder::new("<plugin-name>")
.setup(|app, api| {
app.manage(DummyStore(Default::default()));
let app_ = app.clone();
std::thread::spawn(move || {
loop {
app_.emit("tick", ());
std::thread::sleep(Duration::from_secs(1));
}
});
Ok(())
})

on_navigation

  • 何時:Web 視圖正在嘗試執行導航
  • 原因:驗證導航或追蹤 URL 變更

傳回 false 會取消導航。

src/lib.rs
use tauri::plugin::Builder;
Builder::new("<plugin-name>")
.on_navigation(|window, url| {
println!("window {} is navigating to {}", window.label(), url);
// Cancels the navigation if forbidden
url.scheme() != "forbidden"
})

on_webview_ready

  • 何時:已建立新視窗
  • 原因:為每個視窗執行初始化腳本
src/lib.rs
use tauri::plugin::Builder;
Builder::new("<plugin-name>")
.on_webview_ready(|window| {
window.listen("content-loaded", |event| {
println!("webview content has been loaded");
});
})

on_event

  • 何時:事件迴圈事件
  • 原因:處理核心事件,例如視窗事件、選單事件和應用程式退出請求

透過此生命週期掛鉤,您可以收到任何事件迴圈 事件的通知。

src/lib.rs
use std::{collections::HashMap, fs::write, sync::Mutex};
use tauri::{plugin::Builder, Manager, RunEvent};
struct DummyStore(Mutex<HashMap<String, String>>);
Builder::new("<plugin-name>")
.setup(|app, _api| {
app.manage(DummyStore(Default::default()));
Ok(())
})
.on_event(|app, event| {
match event {
RunEvent::ExitRequested { api, .. } => {
// user requested a window to be closed and there's no windows left
// we can prevent the app from exiting:
api.prevent_exit();
}
RunEvent::Exit => {
// app is going to exit, you can cleanup here
let store = app.state::<DummyStore>();
write(
app.path().app_local_data_dir().unwrap().join("store.json"),
serde_json::to_string(&*store.0.lock().unwrap()).unwrap(),
)
.unwrap();
}
_ => {}
}
})

on_drop

  • 何時:正在解構外掛程式
  • 原因:在外掛程式被銷毀時執行程式碼

如需更多資訊,請參閱 Drop

src/lib.rs
use tauri::plugin::Builder;
Builder::new("<plugin-name>")
.on_drop(|app| {
// plugin has been destroyed...
})

公開 Rust API

專案 desktop.rsmobile.rs 中定義的外掛程式 API 會以與外掛程式名稱相同的結構 (以 Pascal 命名法) 匯出給使用者。 設定外掛程式時,會建立此結構的執行個體並作為狀態進行管理,以便使用者可以使用 Manager 執行個體 (例如 AppHandleAppWindow) 透過外掛程式中定義的擴充特徵在任何時間點擷取它。

例如,global-shortcut plugin 定義了一個 GlobalShortcut 結構,可以使用 GlobalShortcutExt 特徵的 global_shortcut 方法讀取它

src-tauri/src/lib.rs
use tauri_plugin_global_shortcut::GlobalShortcutExt;
tauri::Builder::default()
.plugin(tauri_plugin_global_shortcut::init())
.setup(|app| {
app.global_shortcut().register(...);
Ok(())
})

新增命令

命令在 commands.rs 檔案中定義。 它們是常規的 Tauri 應用程式命令。 它們可以直接存取 AppHandle 和 Window 執行個體、存取狀態,並以與應用程式命令相同的方式取得輸入。 請閱讀命令指南,以取得有關 Tauri 命令的更多詳細資訊。

此命令示範如何透過依賴注入取得對 AppHandleWindow 執行個體的存取權,並採用兩個輸入參數 (on_progressurl)

src/commands.rs
use tauri::{command, ipc::Channel, AppHandle, Runtime, Window};
#[command]
async fn upload<R: Runtime>(app: AppHandle<R>, window: Window<R>, on_progress: Channel, url: String) {
// implement command logic here
on_progress.send(100).unwrap();
}

若要將命令公開給 Webview,您必須掛鉤到 lib.rs 中的 invoke_handler() 呼叫

src/lib.rs
Builder::new("<plugin-name>")
.invoke_handler(tauri::generate_handler![commands::upload])

webview-src/index.ts 中定義綁定函式,以便外掛程式使用者可以輕鬆地在 JavaScript 中呼叫命令

import { invoke, Channel } from '@tauri-apps/api/core'
export async function upload(url: string, onProgressHandler: (progress: number) => void): Promise<void> {
const onProgress = new Channel<number>()
onProgress.onmessage = onProgressHandler
await invoke('plugin:<plugin-name>|upload', { url, onProgress })
}

請務必在測試之前建置 TypeScript 程式碼。

命令權限

預設情況下,您的命令無法由前端存取。 如果您嘗試執行其中一個命令,您將收到拒絕錯誤。 若要實際公開命令,您還需要定義允許每個命令的權限。

權限檔案

權限定義為 permissions 目錄內的 JSON 或 TOML 檔案。 每個檔案都可以定義權限列表、權限集列表以及外掛程式的預設權限。

權限

權限描述外掛程式命令的權限。 它可以允許或拒絕命令列表,並關聯命令特定和全域作用域。

permissions/start-server.toml
"$schema" = "schemas/schema.json"
[[permission]]
identifier = "allow-start-server"
description = "Enables the start_server command."
commands.allow = ["start_server"]
[[permission]]
identifier = "deny-start-server"
description = "Denies the start_server command."
commands.deny = ["start_server"]
作用域

作用域允許您的外掛程式為個別命令定義更深入的限制。 每個權限都可以定義作用域物件列表,這些物件定義了允許或拒絕命令特定的內容,或全域外掛程式。

讓我們定義一個範例結構,該結構將保存 shell 外掛程式允許產生的二進制檔案列表的作用域資料

src/scope.rs
#[derive(Debug, schemars::JsonSchema)]
pub struct Entry {
pub binary: String,
}
命令作用域

您的外掛程式消費者可以在其功能檔案中為特定命令定義作用域 (請參閱文件)。 您可以使用 tauri::ipc::CommandScope 結構讀取命令特定的作用域

src/commands.rs
use tauri::ipc::CommandScope;
use crate::scope::Entry;
async fn spawn<R: tauri::Runtime>(app: tauri::AppHandle<R>, command_scope: CommandScope<'_, Entry>) -> Result<()> {
let allowed = command_scope.allows();
let denied = command_scope.denies();
todo!()
}
全域作用域

當權限未定義任何要允許或拒絕的命令時,它會被視為作用域權限,並且它應該僅為您的外掛程式定義全域作用域

permissions/spawn-node.toml
[[permission]]
identifier = "allow-spawn-node"
description = "This scope permits spawning the `node` binary."
[[permission.scope.allow]]
binary = "node"

您可以使用 tauri::ipc::GlobalScope 結構讀取全域作用域

src/commands.rs
use tauri::ipc::GlobalScope;
use crate::scope::Entry;
async fn spawn<R: tauri::Runtime>(app: tauri::AppHandle<R>, scope: GlobalScope<'_, Entry>) -> Result<()> {
let allowed = scope.allows();
let denied = scope.denies();
todo!()
}
Schema

作用域條目需要 schemars 依賴項來產生 JSON schema,以便外掛程式消費者知道作用域的格式,並在其 IDE 中具有自動完成功能。

若要定義 schema,請先將依賴項新增至您的 Cargo.toml 檔案

# we need to add schemars to both dependencies and build-dependencies because the scope.rs module is shared between the app code and build script
[dependencies]
schemars = "0.8"
[build-dependencies]
schemars = "0.8"

在您的建置腳本中,新增以下程式碼

build.rs
#[path = "src/scope.rs"]
mod scope;
const COMMANDS: &[&str] = &[];
fn main() {
tauri_plugin::Builder::new(COMMANDS)
.global_scope_schema(schemars::schema_for!(scope::Entry))
.build();
}
權限集

權限集是個別權限的群組,可協助使用者以更高等級的抽象化來管理您的外掛程式。 例如,如果單一 API 使用多個命令,或者命令集合之間存在邏輯連接,則您應該定義一個包含它們的集合

permissions/websocket.toml
"$schema" = "schemas/schema.json"
[[set]]
identifier = "allow-websocket"
description = "Allows connecting and sending messages through a WebSocket"
permissions = ["allow-connect", "allow-send"]
預設權限

預設權限是具有識別碼 default 的特殊權限集。 建議您預設啟用必要命令。 例如,如果不允許 request 命令,則 http 外掛程式毫無用處

permissions/default.toml
"$schema" = "schemas/schema.json"
[default]
description = "Allows making HTTP requests"
permissions = ["allow-request"]

自動產生權限

為每個命令定義權限的最簡單方法是使用在 build.rs 檔案中定義的外掛程式建置腳本中定義的自動產生選項。 在 COMMANDS 常數內,以 snake_case 定義命令列表 (應與命令函式名稱相符),Tauri 將自動產生 allow-$commandnamedeny-$commandname 權限。

以下範例產生 allow-uploaddeny-upload 權限

src/commands.rs
const COMMANDS: &[&str] = &["upload"];
fn main() {
tauri_plugin::Builder::new(COMMANDS).build();
}

如需更多資訊,請參閱權限總覽文件。

管理狀態

外掛程式可以像 Tauri 應用程式一樣管理狀態。 請閱讀狀態管理指南以取得更多資訊。


© 2025 Tauri 貢獻者。 CC-BY / MIT