モバイル・プラグインの開発
プラグインは、Kotlin(またはJava)とSwiftで記述されたネイティブ(そのまま)のモバイル・コードを実行できます。デフォルトのプラグイン・テンプレートには、Kotlin を使用した「Android ライブラリ・プロジェクト」と、Rust コードからどのように実行させるのか(トリガーするのか)を説明するモバイル・コマンドのサンプルを含んだ「Swift パッケージ」が含まれています。
プラグイン・プロジェクトの初期化
Section titled “プラグイン・プロジェクトの初期化”新しいプラグイン・プロジェクトを初期化するには、前章 プラグインの開発の手順に従ってください。
既存のプラグインに Android または iOS の機能を追加したい場合は、plugin android init と plugin ios init を使用してモバイル・ライブラリ・プロジェクトをブートストラップ(起動)し、必要な変更を組み込むことができます。
デフォルトのプラグイン・テンプレートは、プラグインの実装を desktop.rs と mobile.rs という二つの別々のモジュールに分割します。
「デスクトップ実装」では Rust コードを用いて機能を実装しますが、「モバイル実装」ではネイティブ・モバイル・コードにメッセージを送信して関数を実行して結果を取得します。両方の実装で共通のロジックが必要な場合は、lib.rs で定義します:
use tauri::Runtime;
impl<R: Runtime> <plugin-name><R> { pub fn do_something(&self) { // ここにデスクトップとモバイルの間で共有される実装(この例では do_something 関数の内容)を定義します }}この実装により、コマンドと Rust コードの両方で使用可能な API を共有するプロセスが簡素化されます。
Android プラグインの開発
Section titled “Android プラグインの開発”Android 用の Tauri プラグインは、app.tauri.plugin.Plugin を拡張し、app.tauri.annotation.TauriPlugin でアノテーションされた「Kotlin クラス」として定義されます。app.tauri.annotation.Command でアノテーションされた各メソッドは、Rust または JavaScript から呼び出すことができます。
アノテーション annotation。データに対して関連する情報を注釈として付与すること。詳しくは Wikipedia を参照してください。
Tauri は、Android プラグインの実装にデフォルトで Kotlin を使用しますが、必要に応じて Java に切り替えることもできます。プラグインを生成後、Android Studio で Kotlin プラグイン・クラスを右クリックし、メニューから「Kotlin ファイルを Java ファイルに変換」オプションを選択します。Kotlin プロジェクトの Java への移行では Android Studio のガイドに従ってください。
iOS プラグインの開発
Section titled “iOS プラグインの開発”iOS 用の Tauri プラグインは、Tauri パッケージの Plugin クラスを拡張する Swift クラスとして定義されています。@objc 属性と (_invoke: Invoke) パラメータを持つ各関数(たとえば @objc private func download(_invoke: Invoke) { } )は、Rust または JavaScript から呼び出すことができます。
プラグインは Swift パッケージ として定義されているため、Swift のパッケージ・マネージャーを使用して依存関係を管理できます。
プラグインの設定
Section titled “プラグインの設定”プラグイン設定の方法に関する詳細については、前章「プラグインの開発」のプラグインの設定 を参照してください。
モバイルのプラグイン・インスタンスには、プラグイン設定用の「ゲッター」コマンドがあります:
import android.app.Activityimport android.webkit.WebViewimport app.tauri.annotation.TauriPluginimport app.tauri.annotation.InvokeArg
@InvokeArgclass Config { var timeout: Int? = 3000}
@TauriPluginclass 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 } }}struct Config: Decodable { let timeout: Int?}
class ExamplePlugin: Plugin { var timeout: Int? = 3000
@objc public override func load(webview: WKWebView) { do { let config = try parseConfig(Config.self) self.timeout = config.timeout } catch {} }}ライフサイクル・イベント
Section titled “ライフサイクル・イベント”プラグインは、いくつかのライフサイクル・イベントにフックできます:
- load: プラグインが Webview に読み込まれたとき
- onNewIntent: Android のみ。アクティビティが再開されたとき
前章の「プラグインの開発」には、上記以外の プラグインのライフサイクル・イベント が記載されています。
「load」
Section titled “「load」”- いつ: プラグインが Webview に読み込まれたとき
- 目的: プラグイン初期化コードの実行
import android.app.Activityimport android.webkit.WebViewimport app.tauri.annotation.TauriPlugin
@TauriPluginclass ExamplePlugin(private val activity: Activity): Plugin(activity) { override fun load(webView: WebView) { // ここでプラグイン設定を実行 }}class ExamplePlugin: Plugin { @objc public override func load(webview: WKWebView) { let timeout = self.config["timeout"] as? Int ?? 30 }}「onNewIntent」
Section titled “「onNewIntent」”注記: このプラグインは Android でのみ利用可能です。
- いつ: アクティビティが再開されたとき。詳細については、Activity#onNewIntent を参照してください。
- 目的: 「通知」がクリックされたときや「ディープリンク」にアクセスしたときなどに、アプリケーションの再起動を処理
import android.app.Activityimport android.content.Intentimport app.tauri.annotation.TauriPlugin
@TauriPluginclass ExamplePlugin(private val activity: Activity): Plugin(activity) { override fun onNewIntent(intent: Intent) { // 新しい「インテント」イベントを処理 }}モバイル・コマンドの追加
Section titled “モバイル・コマンドの追加”それぞれのモバイル・プロジェクトには、Rust コードから呼び出し可能なコマンドを定義できるプラグイン・クラスがあります:
import android.app.Activityimport app.tauri.annotation.Commandimport app.tauri.annotation.TauriPlugin
@TauriPluginclass 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.Activityimport app.tauri.annotation.Commandimport app.tauri.annotation.TauriPlugin
// データの取得を目的としている場合は Dispatchers.IO に変更しますval scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
@TauriPluginclass 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) }}class ExamplePlugin: Plugin { @objc public func openCamera(_ invoke: Invoke) throws { invoke.resolve(["path": "/path/to/photo.jpg"]) }}Rust からモバイル・コマンドを呼び出すには、tauri::plugin::PluginHandle を使用します。
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) }}コマンド引数
Section titled “コマンド引数”引数はシリアル化されてコマンドに渡され、モバイル・プラグインで Invoke::parseArgs 関数を使用して解析可能となり、引数オブジェクトを記述するクラスを受け取ります。
Android
Section titled “Android”Androidでは、引数は @app.tauri.annotation.InvokeArg でアノテーションされたクラスとして定義されます。内部オブジェクトにもアノテーションを付与する必要があります:
import android.app.Activityimport android.webkit.WebViewimport app.tauri.annotation.Commandimport app.tauri.annotation.InvokeArgimport app.tauri.annotation.TauriPlugin
@InvokeArginternal class OpenAppArgs { lateinit var name: String var timeout: Int? = null}
@InvokeArginternal class OpenArgs { lateinit var requiredArg: String var allowEdit: Boolean = false var quality: Int = 100 var app: OpenAppArgs? = null}
@TauriPluginclass ExamplePlugin(private val activity: Activity): Plugin(activity) { @Command fun openCamera(invoke: Invoke) { val args = invoke.parseArgs(OpenArgs::class.java) }}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) { }まず、checkPermissions 関数と requestPermissions 関数をオーバーライドします:
class ExamplePlugin: Plugin { @objc open func checkPermissions(_ invoke: Invoke) { invoke.resolve(["postNotification": "prompt"]) }
@objc public override func requestPermissions(_ invoke: Invoke) { // ここでアクセス権を要求します // 続いて要求を解決します invoke.resolve(["postNotification": "granted"]) }}Tauri は、プラグインに対する二つのコマンド checkPermissions と requestPermissions を自動的に実装します。
この二つのコマンドは、JavaScript または Rust から直接呼び出すことができます。
import { invoke, PermissionState } from '@tauri-apps/api/core'
interface Permissions { postNotification: PermissionState}
// アクセス権の状態を確認const permission = await invoke<Permissions>('plugin:<plugin-name>|checkPermissions')
if (permission.postNotification === 'prompt-with-rationale') { // ユーザーに対してアクセス権が必要な理由についての情報を表示する}
// アクセス権を要求if (permission.postNotification.startsWith('prompt')) { const state = await invoke<Permissions>('plugin:<plugin-name>|requestPermissions', { permissions: ['postNotification'] })}use serde::{Serialize, Deserialize};use tauri::{plugin::PermissionState, Runtime};
#[derive(Deserialize)]#[serde(rename_all = "camelCase")]struct PermissionResponse { pub post_notification: PermissionState,}
#[derive(Serialize)]#[serde(rename_all = "camelCase")]struct RequestPermission { post_notification: bool,}
impl<R: Runtime> Notification<R> { pub fn request_post_notification_permission(&self) -> crate::Result<PermissionState> { self.0 .run_mobile_plugin::<PermissionResponse>("requestPermissions", RequestPermission { post_notification: true }) .map(|r| r.post_notification) .map_err(Into::into) }
pub fn check_permissions(&self) -> crate::Result<PermissionResponse> { self.0 .run_mobile_plugin::<PermissionResponse>("checkPermissions", ()) .map_err(Into::into) }}プラグイン・イベント
Section titled “プラグイン・イベント”プラグインは、trigger 関数を使用していつでもイベントを発行できます:
@TauriPluginclass ExamplePlugin(private val activity: Activity): Plugin(activity) { override fun load(webView: WebView) { trigger("load", JSObject()) }
override fun onNewIntent(intent: Intent) { // 新しい「インテント」イベントを処理 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) }}class ExamplePlugin: Plugin { @objc public override func load(webview: WKWebView) { trigger("load", data: [:]) }
@objc public func openCamera(_ invoke: Invoke) { trigger("camera", data: ["open": true]) }}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 );}【※ この日本語版は、「Nov 13, 2024 英語版」に基づいています】
© 2026 Tauri Contributors. CC-BY / MIT