Rust は安全な言語ですが、unwrap() の失敗などで「パニック(Panic)」が発生し、アプリが突然終了してしまうことがあります。
デフォルトではコンソールに英語のエラーが出るだけでウィンドウが消えてしまうため、ユーザーは「何が起きたのか分からない」状態になります。
これを防ぐために、パニック発生時に「エラーダイアログを出す」「ログファイルに書き出す」といったフック処理を設定できます。
1. ダイアログ表示用クレートの追加
パニック時は Tauri の機能自体も不安定になっている可能性があるため、OS のネイティブダイアログを直接呼べる小さなライブラリ rfd (Rust File Dialog) が便利です。
ターミナルで src-tauri ディレクトリに移動し、以下のコマンドを実行して rfd クレートを追加します。
cd src-tauri
cargo add rfd
2. 実装と動作確認
Tauri v2 の標準構成である src-tauri/src/lib.rs に、以下のコードを実装します。ここではパニックフックの設定に加え、動作確認用に意図的にパニックを起こすコマンド (panic_app) も追加しています。
Rust 側 (src-tauri/src/lib.rs)
run 関数でフックを設定し、テスト用コマンドを登録します。
// src-tauri/src/lib.rs
use std::fs::File;
use std::io::Write;
use std::panic;
// 動作確認用のコマンド:意図的にパニックを起こす
#[tauri::command]
fn panic_app() {
panic!("これはテスト用のパニックです!");
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
// 独自のパニックフックを設定
panic::set_hook(Box::new(|info| {
// 1. エラーメッセージの取り出し
let msg = match info.payload().downcast_ref::<&'static str>() {
Some(s) => *s,
None => match info.payload().downcast_ref::<String>() {
Some(s) => &s[..],
None => "Unknown error",
},
};
// 2. 発生場所(ファイル名・行番号)の取り出し
let location = match info.location() {
Some(l) => format!("File: {}, Line: {}", l.file(), l.line()),
None => "Unknown location".to_string(),
};
let report = format!("申し訳ありません、エラーが発生しました。\n\n内容: {}\n場所: {}", msg, location);
// 3. 標準エラー出力にも出す(開発用)
eprintln!("{}", report);
// 4. ファイルにログ出力(任意)
// カレントディレクトリに保存(実際のアプリでは保存先を適切に設定してください)
if let Ok(mut file) = File::create("crash-report.txt") {
let _ = writeln!(file, "{}", report);
}
// 5. ユーザーへの通知(ダイアログ)
// MessageDialog は同期処理なのでフック内で安全に使えます
// 注意: macOSなど一部のOSではメインスレッド以外からのGUI呼び出しが制限される場合があります
rfd::MessageDialog::new()
.set_title("Crash Report")
.set_description(&report)
.set_level(rfd::MessageLevel::Error)
.show();
}));
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![panic_app]) // テスト用コマンドを登録
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
フロントエンド側 (src/main.ts)
ボタンを押すとバックエンドの panic_app を呼び出す処理を書きます。
※ index.html に <button id="panic-btn">クラッシュさせる</button> がある想定です。
import { invoke } from "@tauri-apps/api/core";
// HTML要素の取得とイベントリスナーの登録
const panicBtn = document.querySelector("#panic-btn");
if (panicBtn) {
panicBtn.addEventListener("click", () => {
invoke("panic_app");
});
}
このボタンを押すと、Rust 側で panic! が発生し、設定した rfd のダイアログが表示されるはずです。通常の開発中(デバッグビルド)では、コンソールにも詳細なバックトレースが表示されます。
解説
panic::set_hook: Rust ランタイムがパニックした瞬間に呼び出す関数を登録します。ここで設定したクロージャが、パニック発生時に実行されます。info: パニックに関する詳細情報(エラーメッセージや発生したファイル・行番号)が入っています。rfd::MessageDialog: OS ネイティブのダイアログを表示します。Tauri のメインウィンドウやイベントループがクラッシュしていても、OS の機能を使ってエラーを通知できるため有用です。