macOS と Windows/Linux では、標準的なメニュー構成が異なります。特に macOS では、メニューバーの一番左(Apple ロゴの右隣)にアプリケーション名が表示される「アプリメニュー」が必要です(About や Quit はここに含まれます)。
Tauri v2 では、JavaScript API (@tauri-apps/plugin-os) を使って実行中のプラットフォームを判定し、動的にメニュー項目を出し分けることができます。
前提条件
プラグインの追加
OS 情報を取得するために、os プラグインを導入します。
npm run tauri add os
src-tauri/src/lib.rs:
.plugin(tauri_plugin_os::init()) を追加します。os プラグインをインストールすると自動的に挿入されるはずですので確認してください。
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_os::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Permissions (権限) の設定
src-tauri/capabilities/default.json に以下の権限を追加します。
{
"permissions": [
...,
"core:menu:default",
"os:default"
]
}
1. フロントエンドで実装する (TypeScript)
type() 関数でプラットフォームを取得し、macOS (macos) の場合のみアプリメニューを追加するロジックを組みます。
import { Menu } from '@tauri-apps/api/menu';
import { type } from '@tauri-apps/plugin-os';
async function createMenu() {
const platform = await type(); // 'macos', 'windows', 'linux', ...
const menuItems = [];
// macOS の場合のみ、アプリケーションメニューを追加
if (platform === 'macos') {
const appMenu = {
text: 'MyApp', // macOSではここには自動的にアプリ名が入る
items: [
{ item: 'About', text: 'MyApp について' },
{ item: 'Separator' },
{ item: 'Quit', text: '終了' },
]
};
menuItems.push(appMenu);
}
// 共通のファイルメニュー
const fileMenu = {
text: 'ファイル',
items: [
{
id: 'new',
text: '新規作成',
accelerator: 'CmdOrCtrl+N'
},
{ item: 'Separator' },
{
id: 'close',
text: '閉じる',
accelerator: 'CmdOrCtrl+W'
}
]
};
menuItems.push(fileMenu);
// アプリケーションメニューとしてセット
const menu = await Menu.new({ items: menuItems });
await menu.setAsAppMenu();
}
createMenu();
2. バックエンドで実装する (Rust)
Rust の場合は #[cfg(target_os = "macos")] などの属性を使用して、コンパイル時にコードを分けるのが一般的で効率的です。
use tauri::menu::{MenuBuilder, SubmenuBuilder, PredefinedMenuItem, MenuItem};
use tauri::Manager;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
// メニュービルダの開始
let mut menu_builder = MenuBuilder::new(app);
// macOS の場合のみアプリメニューを追加
#[cfg(target_os = "macos")]
{
let app_menu = SubmenuBuilder::new(app, "MyApp")
.about(None)
.separator()
.quit()
.build()?;
menu_builder = menu_builder.item(&app_menu);
}
// 共通: ファイルメニュー
let file_menu = SubmenuBuilder::new(app, "ファイル")
.item(&MenuItem::with_id(app, "new", "新規作成", true, Some("CmdOrCtrl+N"))?)
.separator()
.close_window() // Predefined の CloseWindow
.build()?;
menu_builder = menu_builder.item(&file_menu);
// ビルドしてセット
let menu = menu_builder.build()?;
app.set_menu(menu)?;
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
補足
* CmdOrCtrl: アクセラレータの記述で CmdOrCtrl を使うことで、修飾キーの違い(macOSのCommand、WindowsのCtrl)も自動的に吸収されます。
* 条件付きコンパイル: Rust の #[cfg(...)] を使うと、対象外のOSではコード自体がコンパイルされないため、バイナリサイズや実行時のオーバーヘッドを削減できます。