编写插件权限
本练习的目标是更好地理解在编写自己的插件时如何创建插件权限。
在最后,你将能够为插件创建简单的权限。你将获得一个 Tauri 插件示例,其中权限部分是自动生成的,部分是手动设置的。
-
在我们的示例中,我们将使用 Tauri
cli
引导生成一个 Tauri 插件源代码结构。 请确保已安装所有必备 组件 ,并通过运行cargo tauri info
验证你的 Tauri CLI 版本是否正确。输出应表明
tauri-cli
版本为2.x
。 我们将使用pnpm
进行分步说明,但你可以选择其他包管理器,并在命令中相应地替换它。安装最新版本后,你可以继续使用 Tauri CLI 创建插件。
Terminal window mkdir -p tauri-learningcd tauri-learningcargo tauri plugin new testcd tauri-plugin-testpnpm installpnpm buildcargo build -
为了展示一些实用而简单的东西,让我们假设我们的命令将用户输入的内容 写入临时文件夹内的文件中,同时向文件添加一些自定义标题。
我们将命令命名为
write_custom_file
,并在src/commands.rs
中实现它 并将其添加到我们的插件构建器中以暴露给前端。Tauri 的核心程序将自动生成此命令的
allow
和deny
权限,因此我们不需要关心这一点。命令实现:
src/commands.rs use tauri::{AppHandle, command, Runtime};use crate::models::*;use crate::Result;use crate::TestExt;#[command]pub(crate) async fn ping<R: Runtime>(app: AppHandle<R>,payload: PingRequest,) -> Result<PingResponse> {app.test1().ping(payload)}#[command]pub(crate) async fn write_custom_file<R: Runtime>(user_input: String,app: AppHandle<R>,) -> Result<String> {std::fs::write(app.path().temp_dir().unwrap(), user_input)?;Ok("success".to_string())}为你的新命令自动生成内置权限:
src/build.rs const COMMANDS: &[&str] = &["ping", "write_custom_file"];这些内置权限将由 Tauri 构建系统自动生成,并显示在
permissions/autogenerated/commands
文件夹中。默认情况下,将创建enable-<command>
和deny-<command>
权限。 -
上一步是编写实际的命令实现。接下来,我们希望将其暴露给前端,以便其可以被使用。
配置 Tauri 构建器以生成调用处理程序,将前端 IPC 请求传递给新实现的命令:
src/lib.rs pub fn init<R: Runtime>() -> TauriPlugin<R> {Builder::new("test").invoke_handler(tauri::generate_handler![commands::ping,commands::write_custom_file,]).setup(|app, api| {#[cfg(mobile)]let test = mobile::init(app, api)?;#[cfg(desktop)]let test = desktop::init(app, api)?;app.manage(test);// 管理状态,以便命令访问app.manage(MyState::default());Ok(())}).build()}在前端模块中公开新命令。
这一步对于示例应用程序成功导入前端模块至关重要。这是为了方便起见, 不会对安全性产生影响,因为命令处理程序已经生成,该命令也可以从前端手动调用。
guest-js/index.ts import { invoke } from '@tauri-apps/api/core'export async function ping(value: string): Promise<string | null> {return await invoke<{value?: string}>('plugin:test|ping', {payload: {value,},}).then((r) => (r.value ? r.value : null));}export async function writeCustomFile(user_input: string): Promise<string> {return await invoke('plugin:test|write_custom_file',{userInput: user_input});}确保你的包已经构建:
pnpm build -
由于我们的插件应该公开
write_custom_file
命令, 因此我们应该将其添加到我们的default.toml
权限中。将其添加到我们的默认权限集以允许我们刚刚公开的新命令正常运行。
permissions/default.toml "$schema" = "schemas/schema.json"[default]description = "Default permissions for the plugin"permissions = ["allow-ping", "allow-write-custom-file"] -
创建的插件目录结构包含一个
examples/tauri-app
文件夹, 其中有一个可供使用的 Tauri 应用程序来测试该插件。由于我们添加了新命令,因此我们需要稍微修改前端来调用我们的新命令。
src/App.svelte <script>import Greet from './lib/Greet.svelte'import { ping, writeCustomFile } from 'tauri-plugin-test-api'let response = ''function updateResponse(returnValue) {response += `[${new Date().toLocaleTimeString()}]` + (typeof returnValue === 'string' ? returnValue : JSON.stringify(returnValue)) + '<br>'}function _ping() {ping("Pong!").then(updateResponse).catch(updateResponse)}function _writeCustomFile() {writeCustomFile("HELLO FROM TAURI PLUGIN").then(updateResponse).catch(updateResponse)}</script><main class="container"><h1>Welcome to Tauri!</h1><div class="row"><a href="https://vitejs.dev" target="_blank"><img src="/vite.svg" class="logo vite" alt="Vite Logo" /></a><a href="https://tauri.app" target="_blank"><img src="/tauri.svg" class="logo tauri" alt="Tauri Logo" /></a><a href="https://svelte.dev" target="_blank"><img src="/svelte.svg" class="logo svelte" alt="Svelte Logo" /></a></div><p>Click on the Tauri, Vite, and Svelte logos to learn more.</p><div class="row"><Greet /></div><div><button on:click="{_ping}">Ping</button><div>{@html response}</div></div><div><button on:click="{_writeCustomFile}">Write</button><div>{@html response}</div></div></main><style>.logo.vite:hover {filter: drop-shadow(0 0 2em #747bff);}.logo.svelte:hover {filter: drop-shadow(0 0 2em #ff3e00);}</style>运行此程序并按下“Write”按钮,你将看到以下内容:
success你应该在临时文件夹中找到一个
test.txt
文件,其中包含来自我们新实现的插件命令的消息。🥳
© 2025 Tauri Contributors. CC-BY / MIT