tauri-v2 について
tauri-v2 は、Web フロントエンドと Rust バックエンドを使う Tauri v2 のデスクトップ・モバイルアプリ開発向けスキルです。コマンド、権限、状態管理、IPC、ビルドの実装パターンとトラブルシューティングを開発者に提供します。
主な機能
- 01Tauri v2 のコマンドと IPC パターン
- 02ケイパビリティと権限の設定
- 03Rust の状態管理とエラー処理
- 04イベント送信とチャネルストリーミング
- 05ビルド設定とトラブルシューティング
活用シーン
- 01フロントエンドから呼び出す Rust コマンドの登録
- 02権限や IPC の問題の調査
- 03Tauri アプリのモバイルビルド準備
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ robinebers/ openusage --skill tauri-v2インストール後、Claude Code で/tauri-v2を入力して読み込まれたか確認します。
同梱ファイルreferences/capabilities-reference.mdreferences/ipc-patterns.md
詳細
Tauri v2 開発スキル
Web フロントエンドと Rust バックエンドで、クロスプラットフォームのデスクトップアプリやモバイルアプリを構築します。
始める前に
このスキルを使うと、よくあるエラーを 8 件以上防ぎ、トークンを約 60%節約できます。
| 指標 | スキルなし | スキルあり |
|---|---|---|
| セットアップ時間 | 約 2 時間 | 約 30 分 |
| よくあるエラー | 8 件以上 | 0 件 |
| トークン使用量 | 多い(調査) | 少ない(直接的なパターン) |
このスキルで防げる既知の問題
- ケーパビリティ不足によるアクセス拒否エラー
generate_handler!にコマンドが登録されていないことによる IPC の失敗- 型の不一致による状態管理のパニック
- Rust ターゲット不足によるモバイルビルドの失敗
- 開発用 URL の設定ミスによるホワイトスクリーン
クイックスタート
ステップ 1:Tauri コマンドを作成する
// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: String) -> String {
format!("Hello, {}!", name)
}
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
重要な理由: generate_handler![] に含まれていないコマンドは、フロントエンドから呼び出してもエラーが表示されずに失敗します。
ステップ 2:フロントエンドから呼び出す
import { invoke } from '@tauri-apps/api/core';
const greeting = await invoke<string>('greet', { name: 'World' });
console.log(greeting); // "Hello, World!"
重要な理由: @tauri-apps/api/tauri ではなく、@tauri-apps/api/core を使用してください(前者は v1 の API です)。
ステップ 3:必要な権限を追加する
// src-tauri/capabilities/default.json
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"windows": ["main"],
"permissions": ["core:default"]
}
重要な理由: Tauri v2 では、デフォルトですべてが拒否されます。すべての操作に明示的な権限が必要です。
重要なルール
必ず行うこと
- すべてのコマンドを
tauri::generate_handler![cmd1, cmd2, ...]に登録する - 適切なエラー処理のため、コマンドから
Result<T, E>を返す - 複数のコマンドからアクセスする共有状態には
Mutex<T>を使用する - プラグイン機能を使う前にケーパビリティを追加する
- 共有コードには
lib.rsを使用する(モバイルビルドで必須)
絶対に行わないこと
- 非同期コマンドでは借用型(
&str)を使用せず、所有型を使用する - メインスレッドをブロックせず、I/O 操作には非同期処理を使用する
- パスをハードコードせず、Tauri のパス API(
app.path())を使用する - ケーパビリティの設定を省略しない。「安全な」操作にも権限が必要です
よくある間違い
誤り — 非同期処理での借用型:
#[tauri::command]
async fn bad(name: &str) -> String { // Compile error!
name.to_string()
}
正しい — 所有型:
#[tauri::command]
async fn good(name: String) -> String {
name
}
理由: 非同期コマンドでは await ポイントをまたいでデータを借用できません。Tauri では非同期コマンドのパラメーターに所有型が必要です。
既知の問題を防ぐ
| 問題 | 根本原因 | 解決策 |
|---|---|---|
| 「コマンドが見つからない」 | generate_handler! への登録漏れ | コマンドをハンドラーマクロに追加する |
| 「アクセスが拒否された」 | ケーパビリティ不足 | capabilities/default.json に追加する |
| 状態へのアクセス時にパニック | State<T> の型の不一致 | .manage() で指定した型と完全に一致させる |
| 起動時にホワイトスクリーンが表示される | フロントエンドがビルドされていない | 設定の beforeDevCommand を確認する |
| IPC のタイムアウト | 非同期コマンドがブロックされている | ブロッキングコードを削除するか、spawn を使用する |
| モバイルビルドの失敗 | Rust ターゲット不足 | rustup target add <target> を実行する |
設定リファレンス
tauri.conf.json
{
"$schema": "./gen/schemas/desktop-schema.json",
"productName": "my-app",
"version": "1.0.0",
"identifier": "com.example.myapp",
"build": {
"devUrl": "http://localhost:5173",
"frontendDist": "../dist",
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build"
},
"app": {
"windows": [{
"label": "main",
"title": "My App",
"width": 800,
"height": 600
}],
"security": {
"csp": "default-src 'self'; img-src 'self' data:",
"capabilities": ["default"]
}
},
"bundle": {
"active": true,
"targets": "all",
"icon": ["icons/icon.icns", "icons/icon.ico", "icons/icon.png"]
}
}
主な設定:
build.devUrl:フロントエンド開発サーバーのポートと一致させる必要がありますapp.security.capabilities:ケーパビリティファイル識別子の配列
Cargo.toml
[package]
name = "app"
version = "0.1.0"
edition = "2021"
[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
主な設定:
[lib]セクション:モバイルビルドに必須ですcrate-type:クロスプラットフォーム対応には 3 種類すべてを含める必要があります
よく使われるパターン
エラー処理パターン
use thiserror::Error;
#[derive(Debug, Error)]
enum AppError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Not found: {0}")]
NotFound(String),
}
impl serde::Serialize for AppError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::ser::Serializer {
serializer.serialize_str(self.to_string().as_ref())
}
}
#[tauri::command]
fn risky_operation() -> Result<String, AppError> {
Ok("success".into())
}
状態管理パターン
use std::sync::Mutex;
use tauri::State;
struct AppState {
counter: u32,
}
#[tauri::command]
fn increment(state: State<'_, Mutex<AppState>>) -> u32 {
let mut s = state.lock().unwrap();
s.counter += 1;
s.counter
}
// In builder:
tauri::Builder::default()
.manage(Mutex::new(AppState { counter: 0 }))
イベント発行パターン
use tauri::Emitter;
#[tauri::command]
fn start_task(app: tauri::AppHandle) {
std::thread::spawn(move || {
app.emit("task-progress", 50).unwrap();
app.emit("task-complete", "done").unwrap();
});
}
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('task-progress', (e) => {
console.log('Progress:', e.payload);
});
// Call unlisten() when done
チャネルストリーミングパターン
use tauri::ipc::Channel;
#[derive(Clone, serde::Serialize)]
#[serde(tag = "event", content = "data")]
enum DownloadEvent {
Progress { percent: u32 },
Complete { path: String },
}
#[tauri::command]
async fn download(url: String, on_event: Channel<DownloadEvent>) {
for i in 0..=100 {
on_event.send(DownloadEvent::Progress { percent: i }).unwrap();
}
on_event.send(DownloadEvent::Complete { path: "/downloads/file".into() }).unwrap();
}
import { invoke, Channel } from '@tauri-apps/api/core';
const channel = new Channel<DownloadEvent>();
channel.onmessage = (msg) => console.log(msg.event, msg.data);
await invoke('download', { url: 'https://...', onEvent: channel });
同梱リソース
リファレンス
references/ にあります:
capabilities-reference.md- 権限のパターンと例ipc-patterns.md- IPC の詳細な例
注: 特定のトピックを詳しく調べる場合は、上記のリファレンスファイルを参照してください。
依存関係
必須
| パッケージ | バージョン | 用途 |
|---|---|---|
@tauri-apps/cli | ^2.0.0 | CLI ツール |
@tauri-apps/api | ^2.0.0 | フロントエンド API |
tauri | ^2.0.0 | Rust コア |
tauri-build | ^2.0.0 | ビルドスクリプト |
オプション(プラグイン)
| パッケージ | バージョン | 用途 |
|---|---|---|
tauri-plugin-fs | ^2.0.0 | ファイルシステムへのアクセス |
tauri-plugin-dialog | ^2.0.0 | ネイティブダイアログ |
tauri-plugin-shell | ^2.0.0 | シェルコマンド、URL を開く |
tauri-plugin-http | ^2.0.0 | HTTP クライアント |
tauri-plugin-store | ^2.0.0 | キーと値のストレージ |
公式ドキュメント
トラブルシューティング
起動時に画面が白くなる
症状: アプリは起動するものの、画面が白いままです
解決方法:
devUrlがフロントエンドの開発サーバーのポートと一致していることを確認しますbeforeDevCommandで開発サーバーが起動することを確認します- DevTools(Cmd+Option+I / Ctrl+Shift+I)を開いてエラーを確認します
コマンドが undefined を返す
症状: invoke() が期待する値ではなく undefined を返します
解決方法:
- コマンドが
generate_handler![]に登録されていることを確認します - Rust のコマンドが実際に値を返すことを確認します
- 引数名が一致していることを確認します(デフォルトでは JS では camelCase、Rust では snake_case)
モバイルビルドの失敗
症状: Android/iOS のビルドが、ターゲットが見つからないというエラーで失敗します
解決方法:
# Android targets
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
# iOS targets (macOS only)
rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
セットアップチェックリスト
このスキルを使用する前に、以下を確認してください。
-
npx tauri infoに正しい Tauri v2 のバージョンが表示される -
src-tauri/capabilities/default.jsonが存在し、少なくともcore:defaultが設定されている - すべてのコマンドが
generate_handler![]に登録されている -
lib.rsに共有コードが含まれている(モバイルサポート用) - 対象プラットフォームに必要な Rust ターゲットがインストールされている