Tauriの基礎 - プラグインシステム
概要
Tauri v2のプラグインシステムは、アプリケーションのコア機能を拡張するためのモジュラーアーキテクチャである。
プラグインはCargo crate (Rust) とNPMパッケージ (JavaScript/TypeScript) の組み合わせで構成されており、必要な機能のみを選択してアプリケーションに組み込むことができる。
Tauri v2では、多くのコア機能が公式プラグインとして分離され、アプリケーションのサイズを最小限に抑えながら必要な機能を追加できるようになった。
プラグインのインストールは npm run tauri add <プラグイン名> コマンドで行い、自動的にRust側とフロントエンド側の両方に必要な依存関係が追加される。
セキュリティモデルとしてCapabilities設定によるパーミッション管理が導入されており、アプリケーションがアクセスできるリソースや機能を厳密に制御できる。
公式プラグインにはファイルシステム (fs)、ダイアログ (dialog)、HTTPクライアント (http)、シェル実行 (shell)、通知 (notification)、クリップボード操作 (clipboard-manager)、
設定ストア (store) 等があり、コミュニティプラグインも多数公開されている。
プラグインアーキテクチャ
Tauri v2のプラグインは、以下に示す3つのコンポーネントで構成される。
- Rust crate
- バックエンド側のロジックを実装する。
- 命名規則は、tauri-plugin-{name} である。
- Cargo.tomlファイルの
dependenciesに追加される。
- NPMパッケージ
- フロントエンド側のAPIを提供する。
- 命名規則は
@tauri-apps/plugin-{name}である。 - package.jsonファイルの
dependenciesに追加される。
- ネイティブライブラリ (任意)
- AndroidやiOS等のモバイルプラットフォーム向けのネイティブコード
- デスクトップアプリケーションのみの場合は不要である。
このアーキテクチャにより、Rustの高性能なバックエンド処理 と JavaScript / TypeScriptからのAPI呼び出しを両立している。
Tauri v1からの変更点
Tauri v1からv2への移行に伴い、プラグインシステムは大幅に刷新された。
- 機能の分離
- v1ではコアに含まれていた多くの機能が、v2では公式プラグインとして分離された。
- アプリケーションのバンドルサイズを削減できる。
- Capabilitiesベースのセキュリティ
- v1の許可リスト方式から、v2ではCapabilities設定によるパーミッション管理に変更された。
- よりきめ細かいアクセス制御が可能になった。
- 統一されたインストールコマンド
npm run tauri addコマンドにより、RustとNPMの両方の依存関係が自動的に管理される。
インストール方法
自動インストール
プラグインのインストールは、以下に示すコマンドを実行するだけで完了する。
# ファイルシステムプラグインをインストール npm run tauri add fs # ダイアログプラグインをインストール npm run tauri add dialog # HTTPクライアントプラグインをインストール npm run tauri add http
このコマンドは、以下に示す処理を自動的に実行する。
- Cargo.tomlファイルへの依存関係追加
- tauri-plugin-fs が
dependenciesに追加される。
- tauri-plugin-fs が
- package.jsonファイルへの依存関係追加
- @tauri-apps/plugin-fs が
dependenciesに追加される。
- @tauri-apps/plugin-fs が
- Capabilitiesファイルの更新
- 必要なパーミッションが自動的に追加される。
- Rustコードの初期化
- src-tauri/src/lib.rs にプラグインの初期化コードが追加される。
手動インストール
自動インストールがうまく動作しない場合は、手動でインストールすることも可能である。
まず、Rust側の依存関係を追加する。
# src-tauri/Cargo.toml
[dependencies]
tauri-plugin-fs = "2"
次に、NPMパッケージをインストールする。
npm install @tauri-apps/plugin-fs
Rust側でプラグインを初期化する。
// src-tauri/src/lib.rs
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_fs::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
最後に、Capabilitiesファイルにパーミッションを追加する。
{
"permissions": [
"fs:default"
]
}
Capabilities設定
Capabilitiesは、アプリケーションがアクセスできる機能やリソースを定義するセキュリティ設定である。
設定ファイルの場所
Capabilities設定は、以下に示すディレクトリにJSONファイルとして配置する。
src-tauri/capabilities/ ├── default.json # デフォルトのケーパビリティ ├── main-window.json # メインウィンドウ用 └── admin.json # 管理者ウィンドウ用
設定ファイルの構造
基本的なCapabilitiesファイルの構造を以下に示す。
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"fs:default",
"dialog:default"
]
}
| フィールド | 説明 |
|---|---|
identifier |
ケーパビリティの一意識別子 ファイル名と同じにすることが推奨される。 |
description |
ケーパビリティの説明 開発者が理解しやすい説明を記述する。 |
windows |
このケーパビリティを適用するウィンドウ名の配列["*"] で全てのウィンドウに適用できる。
|
permissions |
許可するパーミッションの配列 プラグインごとに定義されたパーミッションを指定する。 |
パーミッションの指定方法
パーミッションは、文字列またはオブジェクトで指定できる。
- 文字列で指定する場合
{ "permissions": [ "fs:default", "fs:allow-read", "fs:allow-write" ] }
- オブジェクトで指定する場合 (スコープ付き)
{ "permissions": [ { "identifier": "fs:allow-read", "allow": [ { "path": "$APPDATA/**" }, { "path": "$RESOURCE/**" } ] } ] }
デフォルトパーミッション
多くのプラグインは、{plugin}:default という形式のデフォルトパーミッションを提供している。
これには、一般的な使用に必要なパーミッションが含まれている。
| パーミッション | 説明 |
|---|---|
core:default |
Tauriコア機能への基本アクセス |
fs:default |
アプリケーションディレクトリへの読み書き |
dialog:default |
ファイルダイアログとメッセージダイアログ |
http:default |
HTTPリクエストの基本機能 |
shell:default |
シェルコマンドの基本実行 |
公式プラグイン一覧
下表に、Tauri v2で提供される公式プラグインの一覧を示す。
| プラグイン名 | 説明 | Android | iOS | Linux | MacOS | Windows |
|---|---|---|---|---|---|---|
| autostart | OS起動時の自動起動 | - | - | ○ | ○ | ○ |
| barcode-scanner | QR/バーコードスキャン | ○ | ○ | - | - | - |
| biometric | 生体認証 | ○ | ○ | - | - | - |
| clipboard-manager | クリップボード操作 | ○ | ○ | ○ | ○ | ○ |
| cli | コマンドライン引数解析 | - | - | ○ | ○ | ○ |
| deep-link | URLハンドラー設定 | ○ | ○ | ○ | ○ | ○ |
| dialog | ネイティブダイアログ | ○ | ○ | ○ | ○ | ○ |
| fs | ファイルシステムアクセス | ○ | ○ | ○ | ○ | ○ |
| geolocation | 位置情報 | ○ | ○ | - | - | - |
| global-shortcut | グローバルショートカット | - | - | ○ | ○ | ○ |
| haptics | 触覚フィードバック | ○ | ○ | - | - | - |
| http | HTTPクライアント | ○ | ○ | ○ | ○ | ○ |
| localhost | ローカルサーバー | - | - | ○ | ○ | ○ |
| log | ログ出力 | ○ | ○ | ○ | ○ | ○ |
| nfc | NFC操作 | ○ | ○ | - | - | - |
| notification | デスクトップ通知 | ○ | ○ | ○ | ○ | ○ |
| opener | 外部アプリで開く | ○ | ○ | ○ | ○ | ○ |
| os | OS情報 | ○ | ○ | ○ | ○ | ○ |
| persisted-scope | スコープ永続化 | ○ | ○ | ○ | ○ | ○ |
| positioner | ウィンドウ位置 | - | - | ○ | ○ | ○ |
| process | プロセス管理 | - | - | ○ | ○ | ○ |
| shell | シェル/外部コマンド | ○ | - | ○ | ○ | ○ |
| single-instance | 単一インスタンス | - | - | ○ | ○ | ○ |
| sql | SQLデータベース | ○ | ○ | ○ | ○ | ○ |
| store | キーバリューストア | ○ | ○ | ○ | ○ | ○ |
| stronghold | 暗号化データベース | ○ | ○ | ○ | ○ | ○ |
| updater | アップデート機能 | - | - | ○ | ○ | ○ |
| upload | ファイルアップロード | ○ | ○ | ○ | ○ | ○ |
| websocket | WebSocket | ○ | ○ | ○ | ○ | ○ |
| window-state | ウィンドウ状態保存 | - | - | ○ | ○ | ○ |
コミュニティプラグイン
公式プラグイン以外にも、コミュニティによって開発されたサードパーティプラグインが存在する。
プラグインの探し方
コミュニティプラグインは、以下に示す場所で見つけることができる。
- GitHub
- tauri-plugin タグで検索する。
- crates.io
- tauri-plugin で検索してRust crateを探す。
- npm
- @tauri-apps/plugin 以外のスコープ付きパッケージを探す。
インストール方法
コミュニティプラグインは、手動でインストールする必要がある場合が多い。
# Rust crateをインストール cargo add tauri-plugin-example # NPMパッケージをインストール npm install tauri-plugin-example-api
注意事項
コミュニティプラグインを使用する場合は、以下に示す事柄に注意する。
- セキュリティ
- 信頼できる作者のプラグインのみを使用する。
- ソースコードを確認することを推奨する。
- メンテナンス状況
- 最終更新日やIssueの状況を確認する。
- 放置されているプラグインは避ける。
- 互換性
- Tauri v2に対応しているか確認する。
- v1向けのプラグインは動作しない場合がある。
サンプルコード
複数のプラグインを組み合わせたReactアプリケーションの例を示す。
以下の例では、ファイルシステム、ダイアログ、通知プラグインを使用して、テキストエディタの基本機能を定義している。
プラグインのインストール
まず、必要なプラグインをインストールする。
npm run tauri add fs npm run tauri add dialog npm run tauri add notification
Reactコンポーネントの定義
import { useState, useCallback } from 'react';
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
import { open, save, ask } from '@tauri-apps/plugin-dialog';
import { sendNotification } from '@tauri-apps/plugin-notification';
// テキストエディタコンポーネント
function TextEditor() {
const [content, setContent] = useState<string>('');
const [filePath, setFilePath] = useState<string | null>(null);
const [isModified, setIsModified] = useState<boolean>(false);
// ファイルを開く処理
const handleOpen = useCallback(async () => {
// 保存確認
if (isModified) {
const shouldSave = await ask('未保存の変更があります。保存しますか?', {
title: '確認',
kind: 'warning'
});
if (shouldSave) {
await handleSave();
}
}
// ファイル選択ダイアログを表示
const selectedPath = await open({
multiple: false,
filters: [
{ name: 'テキストファイル', extensions: ['txt', 'md'] },
{ name: '全てのファイル', extensions: ['*'] }
]
});
if (selectedPath && typeof selectedPath === 'string') {
try {
// ファイルの内容を読み込む
const text = await readTextFile(selectedPath);
setContent(text);
setFilePath(selectedPath);
setIsModified(false);
// 通知を送信
await sendNotification({
title: 'ファイルを開きました',
body: selectedPath
});
}
catch (error) {
console.error('ファイルの読み込みに失敗しました:', error);
await sendNotification({
title: 'エラー',
body: 'ファイルの読み込みに失敗しました'
});
}
}
}, [isModified]);
// ファイルを保存する処理
const handleSave = useCallback(async () => {
let targetPath = filePath;
// ファイルパスがない場合は保存ダイアログを表示
if (!targetPath) {
targetPath = await save({
filters: [
{ name: 'テキストファイル', extensions: ['txt'] }
],
defaultPath: 'untitled.txt'
}) as string | null;
}
if (targetPath) {
try {
// ファイルに書き込む
await writeTextFile(targetPath, content);
setFilePath(targetPath);
setIsModified(false);
await sendNotification({
title: '保存完了',
body: targetPath
});
}
catch (error) {
console.error('ファイルの保存に失敗しました:', error);
await sendNotification({
title: 'エラー',
body: 'ファイルの保存に失敗しました'
});
}
}
}, [content, filePath]);
// テキスト変更時の処理
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setContent(e.target.value);
setIsModified(true);
};
return (
<div className="text-editor">
<div className="toolbar">
<button onClick={handleOpen}>開く</button>
<button onClick={handleSave}>保存</button>
<span>{filePath || '未保存'}</span>
{isModified && <span>*</span>}
</div>
<textarea
value={content}
onChange={handleChange}
placeholder="ここにテキストを入力..."
/>
</div>
);
}
export default TextEditor;
Capabilities設定
このアプリケーションには、以下に示すCapabilities設定が必要である。
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Text Editor Capability",
"windows": ["main"],
"permissions": [
"core:default",
"fs:default",
"dialog:default",
"notification:default"
]
}
トラブルシューティング
プラグインが認識されない場合
プラグインが正しく認識されない場合は、以下に示す項目を確認する。
- 依存関係の確認
- Cargo.tomlとpackage.jsonの両方に依存関係が追加されているか確認する。
- Cargo.tomlとpackage.jsonの両方に依存関係が追加されているか確認する。
- 初期化コードの確認
- src-tauri/src/lib.rs ファイルにプラグインの初期化コードが追加されているか確認する。
- src-tauri/src/lib.rs ファイルにプラグインの初期化コードが追加されているか確認する。
- ビルドの実行
npm run tauri buildまたはnpm run tauri devコマンドを再実行する。
パーミッションエラーが発生する場合
プラグインのAPIを呼び出した時にパーミッションエラーが発生する場合は、Capabilities設定を確認する。
- エラーメッセージの確認
- コンソールに出力されるエラーメッセージから、必要なパーミッションを特定する。
- Capabilitiesファイルの確認
- src-tauri/capabilities/default.json ファイルに必要なパーミッションが含まれているか確認する。
- スコープ設定の確認
- ファイルシステム等、スコープ設定が必要なプラグインの場合は、allow / denyを確認する。
ビルドエラーが発生する場合
ビルド時にエラーが発生する場合は、以下に示す事柄を確認する。
- Rustバージョンの確認
rustc --versionコマンドを実行して、Rustのバージョンを確認する。- Tauri v2はRust 1.70以降を必要とする。
- 依存関係の更新
cargo updateコマンドを実行して、で依存関係を更新する。
- キャッシュのクリア
cargo cleanコマンドを実行して、でビルドキャッシュをクリアする。
参考リンク