desktop-framework-tauri について
desktop-framework-tauriは、Tauri 2.xでデスクトップアプリやモバイルアプリを開発する人向けのスキルです。Rustとフロントエンドのコマンド連携、権限、プラグイン、各種機能、パッケージ化を解説します。
主な機能
- 01フロントエンドから呼び出すRustコマンド
- 02ケイパビリティと権限の設定
- 03共有状態とバックエンドイベント
- 04プラグインの導入と登録
- 05ウィンドウ、トレイ、パッケージ化の手法
活用シーン
- 01Tauriデスクトップアプリの開発
- 02フロントエンドからRustコマンドを呼び出す連携
- 03ケイパビリティ権限によるアクセス制限
- 04アプリのパッケージ化やウィンドウ・トレイ機能の追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents-inc/ skills --skill desktop-framework-tauriインストール後、Claude Code で/desktop-framework-tauriを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.yamlreference.mdexamples/core.mdpackaging.mdplatform.mdplugins.mdsecurity.md詳細
Tauri 2.x デスクトップ・モバイルアプリ
クイックガイド: Tauri 2.x は、Rust バックエンドとシステムの WebView(Chromium は同梱しません)を使用します。
#[tauri::command]で Rust コマンドを定義し、フロントエンドから@tauri-apps/api/coreのinvoke()を使って呼び出します。機密性の高い操作にはすべて、capability ファイルで明示的な権限付与が必要です。プラグインは Cargo クレートと npm パッケージを組み合わせてインストールします。Tauri 2 はデスクトップ(Windows、macOS、Linux)とモバイル(iOS、Android)をサポートします。現在のバージョン: Tauri 2.x(安定版、2024年以降)。Tauri 1.x はレガシーであり、根本的に異なるセキュリティモデル(allowlist と capabilities)を使用します。
<critical_requirements>
重要:このスキルを使用する前に
すべてのコードは、CLAUDE.md のプロジェクト規約(kebab-case、名前付きエクスポート、インポート順序、
import type、名前付き定数)に従う必要があります
(Tauri 2.x の capability/permission システムを必ず使用してください。v1 の allowlist は削除されています)
(すべてのコマンドを tauri::generate_handler![] に必ず登録してください。未登録のコマンドは invoke 時にエラーなく失敗します)
(プラグインの権限を必ず capability ファイルに追加してください。必要な権限がないプラグインは実行時エラーを発生させます)
(モバイルをサポートする場合、pub fn run() に #[cfg_attr(mobile, tauri::mobile_entry_point)] を必ず使用してください)
(invoke() には @tauri-apps/api/core を必ず使用してください。v1 の削除済みパス @tauri-apps/api/tauri は使用しないでください)
</critical_requirements>
自動検出: Tauri、tauri.conf.json、src-tauri、tauri::command、tauri::Builder、invoke、@tauri-apps/api、tauri-plugin、capabilities、#[tauri::command]、generate_handler、AppHandle、WebviewWindow、TrayIconBuilder
使用する場面:
- システム WebView と Rust バックエンドを使用するデスクトップアプリの構築
- Rust コマンドの定義と、フロントエンドの JavaScript/TypeScript からの呼び出し
- capability/permission セキュリティモデルの設定
- 公式 Tauri プラグイン(fs、dialog、http、notification、store、shell など)の使用
- システムトレイ、ウィンドウ管理、メニュー
- デスクトップアプリまたはモバイルアプリのパッケージ化と配布
- Tauri v1 から v2 への移行
使用しない場面:
- フロントエンドフレームワークのパターン(コンポーネントアーキテクチャ、状態管理、ルーティングには、それぞれのフレームワーク用スキルを使用してください)
- Tauri API に関係しない一般的な Rust プログラミング
- ビルドツールの設定(バンドラー、開発サーバーには、別のツール用スキルを使用してください)
- Chromium の全機能(WebRTC、Chrome DevTools Protocol、Chrome 拡張機能)が必要な場合(代替手段を検討してください)
対象となる主なパターン:
- Rust コマンドとフロントエンドの invoke ブリッジ(examples/core.md)
app.manage()とtauri::State<T>による状態管理(examples/core.md)- イベントシステム:フロントエンドとバックエンド間の送受信・リスニング(examples/core.md)
- permission/capability システム(examples/security.md)
- 公式プラグインのインストールと使用(examples/plugins.md)
- ウィンドウ管理、システムトレイ、メニュー(examples/platform.md)
- パッケージ化と配布(examples/packaging.md)
詳細なリソース:
- examples/core.md - コマンド、invoke、状態、イベント、非同期コマンド、エラー処理
- examples/security.md - capabilities、permissions、スコープ、CSP、カスタム権限
- examples/plugins.md - 公式プラグインレジストリ、インストール方法、一般的なプラグイン
- examples/platform.md - Windows、システムトレイ、メニュー、複数ウィンドウ、WebView 管理
- examples/packaging.md - ビルド設定、プラットフォームターゲット、アップデーター、CI/CD
- reference.md - CLI コマンド、設定リファレンス、パス変数、移行チェックリスト
## 設計思想
Tauri はセキュリティを最優先し、小型で、ネイティブです。Chromium をバンドルする代わりに OS のシステム WebView を使用するため、バイナリサイズは他の選択肢の 10〜100 分の 1 になります。Rust バックエンドにより、メモリ安全性とネイティブのパフォーマンスを実現します。権限システムは最小権限のアクセスを徹底し、明示的に許可されない限り、何も許可されません。
Tauri と他の選択肢――Tauri が適している場合:
- バイナリサイズを小さくしたい場合(5〜15 MB、他の選択肢は 150 MB 以上)
- ブラウザーエンジンをバンドルせずに、OS とネイティブに連携したい場合
- 細かな権限を設定できる、強固なセキュリティモデルが必要な場合
- バックエンドのロジックに Rust を使うことに抵抗がない場合
- 同じコードベースからモバイルに対応する必要がある場合(iOS/Android)
Tauri が適していない可能性がある場合:
- プラットフォーム間で同一のレンダリングが保証される必要がある場合(Tauri は OS の WebView を使用するため、差異があります)
- Chrome 固有の API(WebRTC、Chrome 拡張機能、Pepper プラグイン)が必要な場合
- チームに Rust の経験がなく、習得に投資できない場合
- 古い Windows WebView2 バージョンでは利用できない WebView2 の機能が必要な場合
コアパターン
パターン 1:Rust コマンドとフロントエンドからの呼び出し
Rust で #[tauri::command] を使ってコマンドを定義し、generate_handler![] に登録して、フロントエンドから呼び出します。コマンドは引数、戻り値、非同期処理、エラー処理をサポートしています。
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
// Register in main.rs or lib.rs
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
import { invoke } from "@tauri-apps/api/core";
const greeting = await invoke<string>("greet", { name: "World" });
**重要な点:**引数は単一のオブジェクトとして渡されます。Rust のパラメーター名はオブジェクトのキーと一致させる必要があります。コマンドを generate_handler![] に登録し忘れると、何も通知されずに失敗します。非同期コマンド、エラー処理、状態へのアクセスについては、examples/core.md を参照してください。
パターン 2:権限/ケイパビリティシステム
Tauri 2 のすべてのアプリには、権限を付与するケイパビリティファイルが少なくとも 1 つ必要です。権限がないと、プラグインやコア API の呼び出しは実行時に失敗します。
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main-capability",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"shell:allow-open",
"dialog:default",
{
"identifier": "fs:allow-write-text-file",
"allow": [{ "path": "$APPDATA/*" }]
}
]
}
**重要な点:**権限は特定のウィンドウに限定されます。パス変数($APPDATA、$HOME など)を使って、ファイルシステムへのアクセスを制限してください。v1 の許可リストは完全に削除されています。権限モデルの全容については、examples/security.md を参照してください。
パターン 3:状態管理
app.manage() と tauri::State<T> を使って、コマンド間で状態を共有します。変更可能な状態は、Mutex または RwLock でラップしてください。
use std::sync::Mutex;
struct AppState {
counter: Mutex<i32>,
}
#[tauri::command]
fn increment(state: tauri::State<AppState>) -> i32 {
let mut counter = state.counter.lock().unwrap();
*counter += 1;
*counter
}
**重要な点:**コマンドのパラメーターとして宣言すると、tauri::State<T> は自動的に注入されます。この型は Send + Sync を実装している必要があります。パターンの全容については、examples/core.md を参照してください。
パターン 4:イベントシステム
フロントエンドとバックエンド間で双方向のイベントを扱います。フロントエンドでは emit()/listen() を使い、バックエンドでは app.emit()/app.listen() を使います。
import { listen } from "@tauri-apps/api/event";
const unlisten = await listen<string>("download-progress", (event) => {
console.log(`Progress: ${event.payload}`);
});
// Clean up when done
unlisten();
// Emit from backend to all windows
app.emit("download-progress", "50%").unwrap();
**重要な点:**メモリリークを防ぐため、必ずリッスン解除関数を呼び出してください。イベントの型は文字列です。一貫した命名規則を使用してください。対象ウィンドウへのイベントやチャネルについては、examples/core.md を参照してください。
パターン 5:プラグインのインストールパターン
公式プラグインはすべて、Rust クレートと npm パッケージを組み合わせてインストールします。各プラグインには、ケイパビリティファイルでの権限設定が必要です。
# 1. Add Rust crate
cargo add tauri-plugin-store
# 2. Add JS bindings
npm add @tauri-apps/plugin-store
# 3. Register plugin in Rust
tauri::Builder::default()
.plugin(tauri_plugin_store::Builder::new().build())
# 4. Add permission to capability file
# "store:allow-get", "store:allow-set"
**重要な点:**4 つの手順(クレート、npm、登録、権限)のいずれかが欠けると、コンパイルエラーではなく実行時エラーが発生します。プラグインの一覧については、examples/plugins.md を参照してください。
パターン 6:システムトレイ
メニューとイベントハンドラーを備えたシステムトレイアイコンを作成します。
use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent};
use tauri::menu::{MenuBuilder, MenuItemBuilder};
tauri::Builder::default()
.setup(|app| {
let toggle = MenuItemBuilder::with_id("toggle", "Toggle").build(app)?;
let menu = MenuBuilder::new(app).items(&[&toggle]).build()?;
TrayIconBuilder::new()
.menu(&menu)
.on_menu_event(move |_app, event| match event.id().as_ref() {
"toggle" => println!("toggle clicked"),
_ => (),
})
.on_tray_icon_event(|tray, event| {
if let TrayIconEvent::Click {
button: MouseButton::Left,
button_state: MouseButtonState::Up, ..
} = event {
let app = tray.app_handle();
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}
})
.build(app)?;
Ok(())
})
**重要な点:**Tauri 2 では、SystemTray は TrayIconBuilder に置き換えられています。メニューイベントとトレイアイコンイベントは別々に処理します。システムトレイのパターンの全容については、examples/platform.md を参照してください。
<decision_framework>
判断のフレームワーク
Tauri 2 アプリのアーキテクチャ
Where does this logic belong?
|-- Pure UI rendering, user interaction?
| +-- Frontend (JavaScript/TypeScript in webview)
|-- File system, network, OS integration, heavy computation?
| +-- Rust backend (Tauri commands)
|-- Sensitive operation (file write, shell exec, HTTP)?
| +-- Rust command + explicit permission in capability file
+-- Shared state between commands?
+-- app.manage() with Mutex/RwLock wrapper
コマンドの設計
How to structure the command?
|-- Returns data synchronously?
| +-- Regular #[tauri::command] fn
|-- Needs I/O, network, or long computation?
| +-- async #[tauri::command] with Result<T, E>
|-- Needs to access managed state?
| +-- Add tauri::State<T> parameter
|-- Needs app handle (emit events, manage windows)?
| +-- Add app: tauri::AppHandle parameter
+-- Needs to stream data to frontend?
+-- Use tauri::ipc::Channel<T> parameter
プラグインの選定
Need OS integration?
|-- File system access?
| +-- tauri-plugin-fs
|-- File/folder picker dialog?
| +-- tauri-plugin-dialog
|-- HTTP requests from backend?
| +-- tauri-plugin-http
|-- Persistent key-value storage?
| +-- tauri-plugin-store
|-- System notifications?
| +-- tauri-plugin-notification
|-- Run external processes?
| +-- tauri-plugin-shell
|-- Auto-update?
| +-- tauri-plugin-updater
|-- Clipboard?
| +-- tauri-plugin-clipboard-manager
|-- Deep links (custom URL scheme)?
| +-- tauri-plugin-deep-link
+-- Launch on system startup?
+-- tauri-plugin-autostart
CLI コマンドと設定のリファレンスについては、reference.md を参照してください。
</decision_framework>
<red_flags>
重大な注意事項
優先度:高
@tauri-apps/api/tauriのインポートパスを使用する(v2 で削除されています。@tauri-apps/api/coreを使用してください)tauri.conf.jsonで v1 のallowlistを使用する(v2 では capability ファイルに置き換えられています)generate_handler![]へのコマンドの登録を忘れる(コンパイルエラーが発生せず、失敗が通知されません)- capability ファイルにプラグインの権限がない(コンパイルエラーではなく、実行時エラーが発生します)
SystemTrayAPI を使用する(v2 で削除されています。tauri::trayのTrayIconBuilderを使用してください)tauri::api::*を使用する(v2 で削除され、機能はプラグインに移行しました)invoke()をawaitせずに呼び出す(値ではなく Promise が返されます)run()に#[cfg_attr(mobile, tauri::mobile_entry_point)]がない(モバイルビルドが失敗します)
優先度:中
- イベントリスナーをクリーンアップしない(
listen()の後に unlisten を呼び出さないと、メモリリークが発生します) - コマンドで
Resultを返さずにunwrap()を使用する(コマンドがクラッシュし、フロントエンドにエラーが通知されません) - 範囲が広すぎる権限を付与する(パスの範囲指定なしで
fs:allow-read-fileを許可するなど) - Tauri のパス変数(
$APPDATA、$HOME、$RESOURCE)を使わずにパスをハードコードする - 可変の管理状態に
Mutex/RwLockを使用しない(データ競合が発生します)
よくある間違い:
- Rust のパラメーター名と JS の invoke オブジェクトのキーで、コマンド引数の名前が一致していない
- プラグインのインストール時に npm パッケージを忘れる(Cargo クレートだけを追加する)
- 設定で
app.withGlobalTauri: trueを指定せずにwindow.__TAURI__を使用する - プラットフォーム間で WebView の描画が同一だと想定する(Windows の WebView2、macOS の WebKit、Linux の WebKitGTK)
- 非同期コマンドで
Resultのエラーケースを処理しない(フロントエンドで未処理の Promise 拒否が発生します)
注意点とエッジケース:
- capability のスコープ:権限はウィンドウごとに設定されます。セカンダリウィンドウには独自の capability が必要です。または、
windowsに追加する必要があります - パス変数:
$APPDATA、$RESOURCE、$HOMEなどは Tauri 固有のものであり、環境変数ではありません - モバイルでの違い:一部のプラグインはデスクトップ専用です(shell、autostart、global-shortcut)。プラグインのドキュメントを確認してください
- Windows の WebView2:WebView2 ランタイムが必要です(インストーラーにデフォルトで同梱されていますが、古い Windows 10 では保証されません)
- シリアライズ:コマンドの引数と戻り値は
serde::Serialize/Deserializeを実装する必要があります。複雑な型には derive マクロが必要です - 開発サーバー:
tauri devはフロントエンドの開発サーバーにプロキシします。devUrlはフロントエンドのビルドツールではなく、tauri.conf.jsonで設定してください - ビルドサイズ:Tauri のバイナリは 5~15 MB ですが、Rust のコンパイルには時間がかかります。クリーンビルドには 2~5 分かかると想定してください
</red_flags>
<critical_reminders>
重要な注意事項
すべてのコードは、CLAUDE.md のプロジェクト規約に従う必要があります(kebab-case、名前付きエクスポート、インポート順序、
import type、名前付き定数)
(Tauri 2.x の capability/permission システムを必ず使用してください。v1 の allowlist は削除されています)
(すべてのコマンドを tauri::generate_handler![] に必ず登録してください。未登録のコマンドは invoke 時に通知なしで失敗します)
(プラグインの権限を必ず capability ファイルに追加してください。権限が不足しているプラグインは実行時エラーを発生させます)
(モバイルをサポートするには、pub fn run() に #[cfg_attr(mobile, tauri::mobile_entry_point)] を必ず指定してください)
(invoke() には v1 で削除された @tauri-apps/api/tauri のパスではなく、@tauri-apps/api/core を必ず使用してください)
これらのルールに従わないと、コマンドの通知なしの失敗、実行時の権限エラー、またはモバイルビルドの不具合が発生します。
</critical_reminders>