跳到內容
Tauri

行動外掛程式開發

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

初始化外掛程式專案

請按照外掛程式開發指南中的步驟初始化新的外掛程式專案。

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

預設外掛程式範本將外掛程式的實作拆分為兩個獨立的模組:desktop.rsmobile.rs

桌面實作使用 Rust 程式碼來實作功能,而行動實作則將訊息傳送至原生行動程式碼以執行函式並取回結果。如果跨兩個實作都需要共用邏輯,則可以在 lib.rs 中定義

src/lib.rs
use tauri::Runtime;
impl<R: Runtime> <plugin-name><R> {
pub fn do_something(&self) {
// do something that is a shared implementation between desktop and mobile
}
}

此實作簡化了共用 API 的流程,該 API 可供命令和 Rust 程式碼使用。

開發 Android 外掛程式

Android 的 Tauri 外掛程式定義為擴展 app.tauri.plugin.Plugin 的 Kotlin 類別,並使用 app.tauri.annotation.TauriPlugin 註解。每個使用 app.tauri.annotation.Command 註解的方法都可以由 Rust 或 JavaScript 呼叫。

Tauri 預設使用 Kotlin 進行 Android 外掛程式實作,但如果您願意,也可以切換到 Java。產生外掛程式後,在 Android Studio 中右鍵點擊 Kotlin 外掛程式類別,然後從選單中選擇「Convert Kotlin file to Java file」選項。Android Studio 將引導您完成專案遷移到 Java。

開發 iOS 外掛程式

iOS 的 Tauri 外掛程式定義為從 Tauri 套件擴展 Plugin 類別的 Swift 類別。每個具有 @objc 屬性和 (_ invoke: Invoke) 參數的函式(例如 @objc private func download(_ invoke: Invoke) { })都可以由 Rust 或 JavaScript 呼叫。

該外掛程式定義為 Swift 套件,以便您可以使用其套件管理器來管理依賴項。

外掛程式設定

有關開發外掛程式設定的更多詳細資訊,請參閱外掛程式開發指南的外掛程式設定章節

行動裝置上的外掛程式實例具有外掛程式設定的 getter

import android.app.Activity
import android.webkit.WebView
import app.tauri.annotation.TauriPlugin
import app.tauri.annotation.InvokeArg
@InvokeArg
class Config {
var timeout: Int? = 3000
}
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
private var timeout: Int? = 3000
override fun load(webView: WebView) {
getConfig(Config::class.java).let {
this.timeout = it.timeout
}
}
}

生命週期事件

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

  • load:當外掛程式載入到 web view 時
  • onNewIntent:僅限 Android,當 activity 重新啟動時

外掛程式開發指南中還有外掛程式的其他生命週期事件

load

  • 何時:當外掛程式載入到 web view 時
  • 原因:執行外掛程式初始化程式碼
import android.app.Activity
import android.webkit.WebView
import app.tauri.annotation.TauriPlugin
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
override fun load(webView: WebView) {
// perform plugin setup here
}
}

onNewIntent

注意:這僅適用於 Android。

  • 何時:當 activity 重新啟動時。請參閱 Activity#onNewIntent 以取得更多資訊。
  • 原因:處理應用程式重新啟動,例如當點擊通知或存取深度連結時。
import android.app.Activity
import android.content.Intent
import app.tauri.annotation.TauriPlugin
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
override fun onNewIntent(intent: Intent) {
// handle new intent event
}
}

新增行動命令

在各自的行動專案中,有一個外掛程式類別,可以在其中定義可由 Rust 程式碼呼叫的命令

import android.app.Activity
import app.tauri.annotation.Command
import app.tauri.annotation.TauriPlugin
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
@Command
fun openCamera(invoke: Invoke) {
val ret = JSObject()
ret.put("path", "/path/to/photo.jpg")
invoke.resolve(ret)
}
}

如果您想使用 Kotlin suspend 函式,則需要使用自訂協程範圍

import android.app.Activity
import app.tauri.annotation.Command
import app.tauri.annotation.TauriPlugin
// Change to Dispatchers.IO if it is intended for fetching data
val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
@Command
fun openCamera(invoke: Invoke) {
scope.launch {
openCameraInner(invoke)
}
}
private suspend fun openCameraInner(invoke: Invoke) {
val ret = JSObject()
ret.put("path", "/path/to/photo.jpg")
invoke.resolve(ret)
}
}

使用 tauri::plugin::PluginHandle 從 Rust 呼叫行動命令

use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use tauri::Runtime;
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CameraRequest {
quality: usize,
allow_edit: bool,
}
#[derive(Deserialize)]
pub struct Photo {
path: PathBuf,
}
impl<R: Runtime> <plugin-name;pascal-case><R> {
pub fn open_camera(&self, payload: CameraRequest) -> crate::Result<Photo> {
self
.0
.run_mobile_plugin("openCamera", payload)
.map_err(Into::into)
}
}

命令引數

引數會序列化為命令,並且可以使用 Invoke::parseArgs 函式在行動外掛程式上進行解析,並採用描述引數物件的類別。

Android

在 Android 上,引數定義為使用 @app.tauri.annotation.InvokeArg 註解的類別。內部物件也必須註解

import android.app.Activity
import android.webkit.WebView
import app.tauri.annotation.Command
import app.tauri.annotation.InvokeArg
import app.tauri.annotation.TauriPlugin
@InvokeArg
internal class OpenAppArgs {
lateinit var name: String
var timeout: Int? = null
}
@InvokeArg
internal class OpenArgs {
lateinit var requiredArg: String
var allowEdit: Boolean = false
var quality: Int = 100
var app: OpenAppArgs? = null
}
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
@Command
fun openCamera(invoke: Invoke) {
val args = invoke.parseArgs(OpenArgs::class.java)
}
}

iOS

在 iOS 上,引數定義為繼承 Decodable 的類別。內部物件也必須繼承 Decodable 協定

class OpenAppArgs: Decodable {
let name: String
var timeout: Int?
}
class OpenArgs: Decodable {
let requiredArg: String
var allowEdit: Bool?
var quality: UInt8?
var app: OpenAppArgs?
}
class ExamplePlugin: Plugin {
@objc public func openCamera(_ invoke: Invoke) throws {
let args = try invoke.parseArgs(OpenArgs.self)
invoke.resolve(["path": "/path/to/photo.jpg"])
}
}

權限

如果外掛程式需要最終使用者的權限,Tauri 簡化了檢查和請求權限的流程。

首先定義所需權限的清單,以及在程式碼中識別每個群組的別名。這在外掛程式 TauriPlugin 註解內完成

@TauriPlugin(
permissions = [
Permission(strings = [Manifest.permission.POST_NOTIFICATIONS], alias = "postNotification")
]
)
class ExamplePlugin(private val activity: Activity): Plugin(activity) { }

Tauri 自動為外掛程式實作兩個命令:checkPermissionsrequestPermissions。這些命令可以直接從 JavaScript 或 Rust 呼叫

import { invoke, PermissionState } from '@tauri-apps/api/core'
interface Permissions {
postNotification: PermissionState
}
// check permission state
const permission = await invoke<Permissions>('plugin:<plugin-name>|checkPermissions')
if (permission.postNotification === 'prompt-with-rationale') {
// show information to the user about why permission is needed
}
// request permission
if (permission.postNotification.startsWith('prompt')) {
const state = await invoke<Permissions>('plugin:<plugin-name>|requestPermissions', { permissions: ['postNotification'] })
}

外掛程式事件

外掛程式可以使用 trigger 函式在任何時間點發射事件

@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
override fun load(webView: WebView) {
trigger("load", JSObject())
}
override fun onNewIntent(intent: Intent) {
// handle new intent event
if (intent.action == Intent.ACTION_VIEW) {
val data = intent.data.toString()
val event = JSObject()
event.put("data", data)
trigger("newIntent", event)
}
}
@Command
fun openCamera(invoke: Invoke) {
val payload = JSObject()
payload.put("open", true)
trigger("camera", payload)
}
}

然後可以使用 addPluginListener 輔助函式從 NPM 套件呼叫輔助函式

import { addPluginListener, PluginListener } from '@tauri-apps/api/core';
export async function onRequest(
handler: (url: string) => void
): Promise<PluginListener> {
return await addPluginListener(
'<plugin-name>',
'event-name',
handler
);
}

© 2025 Tauri Contributors。CC-BY / MIT