Tauri RunEvent::Reopen 是 macOS 专属,移植 Windows 时编译必爆
我在把一个只跑过 macOS 的 Tauri 2 桌面应用接入 Windows 构建流水线时,CI 立刻红了。本地 cargo check 全程绿灯,推上去就在 windows-latest 的 runner 上炸。编译器给出的错误让人愣了一下:枚举变体根本不存在。
现象
GitHub Actions 的 windows-latest job 在 cargo build 阶段报错:
error[E0599]: no variant named `Reopen` found for enum `tauri::RunEvent`
--> src/lib.rs:259:37
|
259 | if let tauri::RunEvent::Reopen { .. } = event {
| ^^^^^^ variant not found in `tauri::RunEvent`
而在 Mac 上,cargo check 和 cargo build 都毫无异常。这段代码一直跑着,用于监听用户点击 Dock 图标时把隐藏到托盘的窗口重新显示出来:
.run(|app_handle, event| {
if let tauri::RunEvent::Reopen { .. } = event {
if let Some(w) = app_handle.get_webview_window("main") {
let _ = w.show();
let _ = w.set_focus();
}
}
})根因
tauri::RunEvent::Reopen 在 Tauri 源码里标注了 #[cfg(target_os = "macos")]。Windows 没有 Dock,这个变体在 Windows 平台的枚举定义里根本不存在——不是运行时找不到,而是编译期字面上就没有这个 variant。
同理还有一批 macOS 专属的菜单 API:SubmenuBuilder 的 .services()、.hide_others()、.show_all() 都是 macOS 菜单栏约定,Windows 编译同样会爆 unused import 或找不到方法。
cargo check / cargo build 默认只编译当前宿主平台的目标。所有被 #[cfg(target_os = "macos")] 保护的 Tauri API——包括 RunEvent::Reopen、Dock 相关菜单项——在 Mac 上永远是合法代码。错误只在交叉编译或 Windows CI 时才浮出水面。如果你的项目从来没有跑过 Windows 构建,这类炸弹可以沉睡很久。
正解
用 #[cfg(target_os = "macos")] 把 Reopen 的 match arm 整体包起来。同时把闭包参数改成带下划线前缀,避免 non-mac 平台触发 unused-variable 警告:
.run(|_app_handle, _event| {
// RunEvent::Reopen 是 macOS 专属变体,Windows 无 Dock,该变体在 win 上不存在
#[cfg(target_os = "macos")]
if let tauri::RunEvent::Reopen { .. } = _event {
if let Some(w) = _app_handle.get_webview_window("main") {
let _ = w.show();
let _ = w.set_focus();
}
}
});对应的 macOS 专属菜单栏,同样把构建块和 use 声明一起圈起来:
use tauri::menu::{Menu, MenuItem}; // 跨平台公用(托盘菜单)
#[cfg(target_os = "macos")]
use tauri::menu::{MenuBuilder, MenuItemBuilder, SubmenuBuilder};
#[cfg(target_os = "macos")]
use tauri::Emitter;
// 在 .setup(|app| { … }) 内部:
#[cfg(target_os = "macos")]
{
// 含 .services() / .hide_others() / .show_all() 的菜单栏构建
app.set_menu(menu_bar)?;
app.on_menu_event(/* … */);
}注意:#[cfg] 可以直接放在 if let 语句之前(语句级属性),不必额外套一层 {} 块。
不需要把整个 run 闭包拆分,只需把 Reopen 的那条 match arm 单独圈住。闭包参数改为 _app_handle / _event,保证 Windows 构建不报 unused warning。Windows CI job 能通过编译,Mac 上行为不变。
排查思路
如果你遇到同类问题,快速排查路径:
- 搜索
RunEvent::的所有用法,查 Tauri 文档 确认哪些变体有cfg门控。 - 搜索
tauri::menu::的.services()/.hide_others()/.show_all(),这三个方法是 macOS 系统菜单约定,Windows 无对应实现。 - 在 Mac 上本地交叉编译验证:
cargo build --target x86_64-pc-windows-msvc(需提前安装 MSVC toolchain),或者直接在 CI 里尽早开一个windows-latestjob——让 Windows CI 成为 Windows 路径的 source of truth,而不是等到发布前才发现。
一句话外卖
macOS-only Tauri app 移植跨平台时,本地
cargo check是哑的——早点在 CI 立一个windows-latestjob,让编译器帮你找出所有#[cfg(target_os = "macos")]漏网的调用点。