スプラッシュスクリーン(起動時表示画面)
この「試作(ラボ)」では、Tauri アプリに基本的なスプラッシュスクリーン機能を実装します。 やりかたは至って単純明快です。スプラッシュスクリーンは、実質的には、アプリがセットアップ関連の負荷の高いタスクを実行している間中、相応のコンテンツを表示する新しいウィンドウを描画し、セットアップが完了したらそのウィンドウを閉じるだけです。
-
プロジェクトの開発を始める前に、セットアップが意図したとおりに動作していることを確認するために、初期テンプレートをビルドして実行することが重要です。
# 正しいディレクトリにいることを確認してくださいcd splashscreen-lab# 依存関係をインストールpnpm install# アプリのビルドと実行pnpm tauri dev
-
新しいウィンドウを追加する最も簡単な方法は、
tauri.conf.jsonに直接追加することです。 起動時に動的にウィンドウを作成することもできますが、簡素化のために、そうはせずに直接登録することにします。mainというラベルのウィンドウが「非表示」ウィンドウとして、splashscreenというラベルのウィンドウが「直接表示」されるウィンドウとして作成されていることを確認してください。その他のオプション項目はどれも、デフォルト設定のままでも、好みに応じて調整しても構いません。src-tauri/tauri.conf.json {"windows": [{"label": "main","visible": false},{"label": "splashscreen","url": "/splashscreen"}]} -
ページの作成を始める前に、表示するコンテンツをいくつか準備する必要があります。 新しいページをどのように展開するのかは、選択したフレームワークによって異なりますが、ほとんどのフレームワークにはページ・ナビゲーションを処理する「ルーター」という考え方があり、Tauri で普通に機能するはずです。そうであれば、あとは新しいスプラッシュスクリーン・ページを生成するだけです。 あるいは、以下で行なうように、コンテンツをホストするための新しい
splashscreen.htmlファイルを作成します。ここで重要なのは、「URL
/splashscreen」にアクセスでき、スプラッシュスクリーンに表示したいコンテンツが表示されることです。この手順を完了したら、アプリをもう一度実行して確かめてみてください。/splashscreen.html <!doctype html><html lang="en"><head><meta charset="UTF-8" /><link rel="stylesheet" href="/src/styles.css" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Tauri App</title></head><body><div class="container"><h1>Tauri used Splash!</h1><div class="row"><h5>It was super effective!</h5></div></div></body></html>
-
一般的に、スプラッシュスクリーンは起動時の重いタスクを隠すことを意図しているため、アプリのフロントエンドとバックエンドでいくつかの重い処理を擬似実行させて見ましょう。
フロントエンドで重い起動処理を擬似実行するには、単純な
setTimeout関数を使用します。一方、バックエンドで重い操作を擬似実行する最も簡単な方法は、Tokio クレートを使用することです。これは、バックエンドで非同期ランタイムを提供するために Tauri が使用する Rust クレートです。Tauri がランタイムを提供する一方で、クレートから再エクスポートしない様々なユーティリティがあるため、そのようなユーティリティにアクセスするために、Tokio クレートをプロジェクトに追加する必要があります。これは Rust エコシステムではごく一般的なやりかたです。
非同期関数では
std::thread::sleepを使用しないでください。非同期関数は、並列ではなく同時実行環境で協調的に実行されます。つまり、Tokio タスクの代わりにこのstd::thread::sleep関数でスレッドをスリープ状態にすると、そのスレッドで実行するようにスケジュールされているすべてのタスクの実行がロックされ、アプリがフリーズします。# `Cargo.toml`ファイルがある場所でこのコマンドを実行cd src-tauri# Tokio crate の追加cargo add tokio# 必要に応じてトップ・フォルダに戻り開発作業を継続# `tauri dev` がどこで実行するかを自動判断cd ..src/main.ts // 以下の内容は既存のコードの下にコピーして貼り付けることができますが、ファイル全体を置き換えないでください。// TypeScript でスリープ機能を実装するためのユーティリティ関数function sleep(seconds: number): Promise<void> {return new Promise(resolve => setTimeout(resolve, seconds * 1000));}// Setup 関数async function setup() {// 非常に重い起動処理タスクを擬似実行console.log('Performing really heavy frontend setup task...')await sleep(3);console.log('Frontend setup task complete!')// フロントエンド・タスクを完了済みとして設定invoke('set_complete', {task: 'frontend'})}// 実質的に JavaScript のメイン関数window.addEventListener("DOMContentLoaded", () => {setup()});/src-tauri/src/lib.rs // 利用する機能をインポートuse std::sync::Mutex;use tauri::async_runtime::spawn;use tauri::{AppHandle, Manager, State};use tokio::time::{sleep, Duration};// 起動関連タスクの完了を追跡するために使用する構造体を作成struct SetupState {frontend_task: bool,backend_task: bool,}// バージョン 2 モバイル対応アプリでのメイン・エントリーポイント#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {// Tauri の起動前ではなく、起動フック部分にコードを記載してください!tauri::Builder::default()// Tauri で管理される `State` を登録する// これには書き込みアクセスが必要なので、`Mutex`でラップします。.manage(Mutex::new(SetupState {frontend_task: false,backend_task: false,}))// 確認に使用するコマンドの追加.invoke_handler(tauri::generate_handler![greet, set_complete])// 起動関連タスクの実行に起動フックを使用// メインループの前に実行されるため、ウィンドウはまだ作成されません.setup(|app| {// 起動を非ブロッキング処理として生成し、実行中にウィンドウを生成・実行可能にします。spawn(setup(app.handle().clone()));// フックは「Ok」という結果を要求しますOk(())})// アプリを実行.run(tauri::generate_context!()).expect("error while running tauri application");}#[tauri::command]fn greet(name: String) -> String {format!("Hello {name} from Rust!")}// 起動タスクの状態を設定するためのカスタム・タスク#[tauri::command]async fn set_complete(app: AppHandle,state: State<'_, Mutex<SetupState>>,task: String,) -> Result<(), ()> {// 書き込みアクセスなしで状態をロックlet mut state_lock = state.lock().unwrap();match task.as_str() {"frontend" => state_lock.frontend_task = true,"backend" => state_lock.backend_task = true,_ => panic!("invalid task completed!"),}// フロントエンド・バックエンド両方のタスクが完了したかどうかを確認if state_lock.backend_task && state_lock.frontend_task {// 起動が完了したら、スプラッシュスクリーンを閉じてメインウィンドウを提示let splash_window = app.get_webview_window("splashscreen").unwrap();let main_window = app.get_webview_window("main").unwrap();splash_window.close().unwrap();main_window.show().unwrap();}Ok(())}// 重い起動タスクを実行する非同期関数async fn setup(app: AppHandle) -> Result<(), ()> {// 重い処理を 3 秒間擬似実行println!("Performing really heavy backend setup task...");sleep(Duration::from_secs(3)).await;println!("Backend setup task completed!");// バックエンドタスクを完了済みとして設定// 入力引数を自分で処理する限り、コマンドは通常の関数として実行できます。set_complete(app.clone(),app.state::<Mutex<SetupState>>(),"backend".to_string(),).await?;Ok(())} -
これでスプラッシュスクリーン・ウィンドウがポップアップ表示され、フロントエンドとバックエンドの両方でそれぞれ 3 秒間の重い起動タスクが実行され、その後スプラッシュスクリーンが消えてメイン・ウィンドウに切り替わります。
一般的に、スプラッシュスクリーンを表示するということは、スプラッシュスクリーンを必要としないほどアプリの読み込み速度を上げることができなかったという敗北を認めることになります。 実際、メイン・ウィンドウを直接表示して、メイン・ウィンドウの隅のどこかに小さなスピナー(進捗表示計)を表示し、バックグラウンドで起動タスクがまだ実行中であることをユーザーに通知する方がどちらかといえばよいでしょう。
ただし、そうは言っても、スプラッシュスクリーンを表示したいというスタイル上の選択があったり、特定のタスクが実行されるまでアプリを起動できなくしたいという特殊な事情がある場合もあります。 スプラッシュスクリーンがあることは決して間違っているというわけではありませんが、必ずしも必要とされない傾向にあり、ユーザーにアプリがあまり最適化されていないと感じさせる可能性があります。
【※ この日本語版は、「Feb 22, 2025 英語版」に基づいています】
© 2025 Tauri Contributors. CC-BY / MIT