记录桌面壳宿主动作失败
桌面壳菜单托盘动作失败改为统一日志记录 桌面壳单实例唤醒失败改为统一日志记录 桌面壳配置门禁禁止宿主动作静默吞错 宿主壳文档同步动作失败处理规则
This commit is contained in:
@@ -2108,6 +2108,14 @@ const requiredRustHostSnippets = [
|
||||
'open_desktop_deep_link_url(window: &WebviewWindow, url: &Url) -> tauri::Result<()>',
|
||||
'window.navigate(target_url)?',
|
||||
'show_main_window(window.app_handle())',
|
||||
'log_desktop_host_event_result("app_menu.show", show_main_window(app))',
|
||||
'log_desktop_host_event_result("app_menu.back", eval_main_window_history_back(app))',
|
||||
'"app_menu.forward"',
|
||||
'eval_main_window_history_forward(app)',
|
||||
'log_desktop_host_event_result("app_menu.reload", reload_main_window(app))',
|
||||
'log_desktop_host_event_result("tray.show", show_main_window(app))',
|
||||
'log_desktop_host_event_result("tray.reload", reload_main_window(app))',
|
||||
'log_desktop_host_event_result("single_instance.show", show_main_window(app))',
|
||||
'DESKTOP_DEEP_LINK_HOSTS',
|
||||
'resolve_desktop_single_instance_action',
|
||||
'tauri_plugin_clipboard_manager::init()',
|
||||
@@ -2715,6 +2723,10 @@ for (const blockedLifecycleSnippet of [
|
||||
'let _ = emit_desktop_image_drop_event(&drop_window',
|
||||
'let _ = window.navigate(target_url)',
|
||||
'let _ = show_main_window(window.app_handle())',
|
||||
'let _ = show_main_window(app)',
|
||||
'let _ = eval_main_window_history_back(app)',
|
||||
'let _ = eval_main_window_history_forward(app)',
|
||||
'let _ = reload_main_window(app)',
|
||||
]) {
|
||||
if (rustHostSource.includes(blockedLifecycleSnippet)) {
|
||||
throw new Error(
|
||||
|
||||
@@ -54,7 +54,7 @@ pub(crate) fn run() {
|
||||
.plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| {
|
||||
match resolve_desktop_single_instance_action() {
|
||||
DesktopSingleInstanceAction::ShowMainWindow => {
|
||||
let _ = show_main_window(app);
|
||||
log_desktop_host_event_result("single_instance.show", show_main_window(app));
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::shell::lifecycle::log_desktop_host_event_result;
|
||||
use crate::shell::tray::{reload_main_window, show_main_window};
|
||||
use tauri::menu::{Menu, MenuItem, PredefinedMenuItem, Submenu};
|
||||
use tauri::Manager;
|
||||
@@ -50,16 +51,19 @@ fn eval_main_window_history_forward(app: &tauri::AppHandle) -> tauri::Result<()>
|
||||
fn handle_desktop_app_menu_action(app: &tauri::AppHandle, action: DesktopAppMenuAction) {
|
||||
match action {
|
||||
DesktopAppMenuAction::ShowMainWindow => {
|
||||
let _ = show_main_window(app);
|
||||
log_desktop_host_event_result("app_menu.show", show_main_window(app));
|
||||
}
|
||||
DesktopAppMenuAction::GoBack => {
|
||||
let _ = eval_main_window_history_back(app);
|
||||
log_desktop_host_event_result("app_menu.back", eval_main_window_history_back(app));
|
||||
}
|
||||
DesktopAppMenuAction::GoForward => {
|
||||
let _ = eval_main_window_history_forward(app);
|
||||
log_desktop_host_event_result(
|
||||
"app_menu.forward",
|
||||
eval_main_window_history_forward(app),
|
||||
);
|
||||
}
|
||||
DesktopAppMenuAction::ReloadMainWindow => {
|
||||
let _ = reload_main_window(app);
|
||||
log_desktop_host_event_result("app_menu.reload", reload_main_window(app));
|
||||
}
|
||||
DesktopAppMenuAction::QuitApp => app.exit(0),
|
||||
DesktopAppMenuAction::Ignore => {}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::shell::lifecycle::{emit_current_desktop_lifecycle_event, emit_desktop_lifecycle_event};
|
||||
use crate::shell::lifecycle::{
|
||||
emit_current_desktop_lifecycle_event, emit_desktop_lifecycle_event,
|
||||
log_desktop_host_event_result,
|
||||
};
|
||||
use tauri::menu::{Menu, MenuItem};
|
||||
use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent};
|
||||
use tauri::{Manager, WebviewWindow, WindowEvent};
|
||||
@@ -81,10 +84,10 @@ pub(crate) fn reload_main_window(app: &tauri::AppHandle) -> tauri::Result<()> {
|
||||
fn handle_desktop_tray_action(app: &tauri::AppHandle, action: DesktopTrayAction) {
|
||||
match action {
|
||||
DesktopTrayAction::ShowMainWindow => {
|
||||
let _ = show_main_window(app);
|
||||
log_desktop_host_event_result("tray.show", show_main_window(app));
|
||||
}
|
||||
DesktopTrayAction::ReloadMainWindow => {
|
||||
let _ = reload_main_window(app);
|
||||
log_desktop_host_event_result("tray.reload", reload_main_window(app));
|
||||
}
|
||||
DesktopTrayAction::QuitApp => app.exit(0),
|
||||
DesktopTrayAction::Ignore => {}
|
||||
|
||||
@@ -2866,6 +2866,13 @@
|
||||
- 影响范围:`apps/desktop-shell/src-tauri/src/shell/deep_link.rs`、`apps/desktop-shell/scripts/check-config.mjs`、宿主壳能力统一协议文档。
|
||||
- 验证方式:`cargo test --manifest-path apps/desktop-shell/src-tauri/Cargo.toml`、`npm run desktop-shell:typecheck`、`npm run check:native-shells`、`npm run check:encoding`、`git diff --check`。
|
||||
|
||||
## 2026-06-20 桌面壳菜单托盘与单实例动作失败不可静默
|
||||
|
||||
- 背景:桌面壳应用菜单、托盘菜单和单实例唤醒是生产用户恢复、刷新和导航主窗口的宿主入口;如果这些动作失败仍被 `let _ = ...` 静默忽略,用户会看到菜单、托盘或二次启动无反应且无法排查。
|
||||
- 决策:应用菜单显示、后退、前进、刷新主窗口,托盘显示、刷新主窗口,以及单实例唤醒主窗口动作失败必须走统一桌面宿主事件日志;配置检查拒绝这些入口继续对主窗口动作使用 `let _ = ...` 静默吞错。
|
||||
- 影响范围:`apps/desktop-shell/src-tauri/src/app.rs`、`apps/desktop-shell/src-tauri/src/shell/menu.rs`、`apps/desktop-shell/src-tauri/src/shell/tray.rs`、`apps/desktop-shell/scripts/check-config.mjs`、宿主壳方案文档。
|
||||
- 验证方式:`cargo test --manifest-path apps/desktop-shell/src-tauri/Cargo.toml`、`npm run desktop-shell:typecheck`、`npm run check:native-shells`、`npm run check:encoding`、`git diff --check`。
|
||||
|
||||
## 2026-06-20 移动壳 ShellApp HostBridge 事件注入必须可执行覆盖
|
||||
|
||||
- 背景:Expo 移动壳声明 `host.events`、`app.lifecycle`、`network.statusChanged` 和 `navigation.canGoBack`,但 ShellApp 真实 AppState、Network 和 WebView 返回栈注入链路需要和扫码链路一样有可执行测试覆盖,不能只靠字符串门禁。
|
||||
|
||||
@@ -419,11 +419,11 @@ GameBridge 禁止:
|
||||
|
||||
2026-06-18 追加:桌面壳 WebView 每次页面加载完成后都会回放当前 `app.lifecycle` 并重新安装 `network.statusChanged` 监听脚本,覆盖托盘刷新、`app.reloadWebView` 和 H5 自刷新后的新 JS 上下文。回放会读取主窗口当前 `is_visible()`、`is_minimized()` 和 `is_focused()`,隐藏或最小化状态下不得误报 active;事件仍只通过 HostBridge message 注入,不开放 Tauri event 插件或额外 command。
|
||||
|
||||
2026-06-18 追加:桌面壳启用 Tauri 真实系统托盘,并复用品牌图标。托盘菜单只提供宿主壳级动作:显示主窗口、刷新主窗口和退出应用;左键点击托盘图标恢复并聚焦主窗口。该能力不进入 HostBridge capability 清单,不向 H5 暴露托盘 API、菜单 API、shell API 或任意窗口控制;如果当前桌面环境无法注册托盘,壳会继续启动主窗口。托盘注册成功时,用户点击主窗口关闭按钮会先通过 `app.lifecycle` 注入 `background` / `hidden`,再隐藏到托盘,必须通过托盘“退出”动作结束应用;托盘恢复、应用菜单显示、单实例唤醒和 deep link 唤醒都会重新显示、取消最小化、聚焦主窗口并回放当前生命周期状态。托盘注册失败时不拦截关闭,避免窗口消失后没有恢复入口。
|
||||
2026-06-18 追加:桌面壳启用 Tauri 真实系统托盘,并复用品牌图标。托盘菜单只提供宿主壳级动作:显示主窗口、刷新主窗口和退出应用;左键点击托盘图标恢复并聚焦主窗口。该能力不进入 HostBridge capability 清单,不向 H5 暴露托盘 API、菜单 API、shell API 或任意窗口控制;如果当前桌面环境无法注册托盘,壳会继续启动主窗口。托盘注册成功时,用户点击主窗口关闭按钮会先通过 `app.lifecycle` 注入 `background` / `hidden`,再隐藏到托盘,必须通过托盘“退出”动作结束应用;托盘恢复、应用菜单显示、单实例唤醒和 deep link 唤醒都会重新显示、取消最小化、聚焦主窗口并回放当前生命周期状态。托盘注册失败时不拦截关闭,避免窗口消失后没有恢复入口;托盘显示和刷新主窗口动作失败必须记录桌面宿主事件日志,不能静默吞错。
|
||||
|
||||
2026-06-18 追加:桌面壳启用 Tauri 应用菜单。`shell/menu.rs` 注册应用菜单、编辑菜单和窗口菜单,其中应用菜单只复用宿主壳级动作:显示主窗口、后退、前进、刷新主窗口和退出应用;后退 / 前进只执行固定 `window.history.back(); true;` 与 `window.history.forward(); true;`,无历史记录时按浏览器 no-op 处理,不新增 HostBridge method,也不接收 H5 payload 或任意脚本;编辑 / 窗口项使用 Tauri 原生预定义菜单项承接系统剪切、复制、粘贴、全选、最小化、最大化和关闭窗口。该能力不进入 HostBridge capability,不向 H5 暴露菜单 API、shell API 或任意窗口控制;应用菜单注册失败视为桌面壳启动失败,避免可分发桌面包缺少系统菜单仍静默运行。
|
||||
2026-06-18 追加:桌面壳启用 Tauri 应用菜单。`shell/menu.rs` 注册应用菜单、编辑菜单和窗口菜单,其中应用菜单只复用宿主壳级动作:显示主窗口、后退、前进、刷新主窗口和退出应用;后退 / 前进只执行固定 `window.history.back(); true;` 与 `window.history.forward(); true;`,无历史记录时按浏览器 no-op 处理,不新增 HostBridge method,也不接收 H5 payload 或任意脚本;编辑 / 窗口项使用 Tauri 原生预定义菜单项承接系统剪切、复制、粘贴、全选、最小化、最大化和关闭窗口。该能力不进入 HostBridge capability,不向 H5 暴露菜单 API、shell API 或任意窗口控制;应用菜单注册失败视为桌面壳启动失败,避免可分发桌面包缺少系统菜单仍静默运行;应用菜单显示、后退、前进和刷新主窗口动作失败必须记录桌面宿主事件日志,不能静默吞错。
|
||||
|
||||
2026-06-18 追加:桌面壳启用 Tauri 单实例。用户重复启动桌面 App 时,新实例会退出并唤醒已有主窗口;该回调只执行显示、取消最小化和聚焦主窗口,不把第二实例的命令行参数或工作目录作为事件透传给 H5。Windows / Linux 上由单实例插件的 `deep-link` feature 把二次实例 URL 交给 deep-link 插件,仍由 `shell/deep_link.rs` 做受控归一。
|
||||
2026-06-18 追加:桌面壳启用 Tauri 单实例。用户重复启动桌面 App 时,新实例会退出并唤醒已有主窗口;该回调只执行显示、取消最小化和聚焦主窗口,不把第二实例的命令行参数或工作目录作为事件透传给 H5。Windows / Linux 上由单实例插件的 `deep-link` feature 把二次实例 URL 交给 deep-link 插件,仍由 `shell/deep_link.rs` 做受控归一;单实例唤醒主窗口失败必须记录桌面宿主事件日志,不能静默吞错。
|
||||
|
||||
2026-06-18 追加:桌面壳启用 Tauri 窗口状态持久化。`shell/window_state.rs` 只配置 `tauri-plugin-window-state` 保存主窗口大小、位置和最大化状态,并排除可见性、全屏和装饰状态;插件注册顺序固定为 single-instance 优先,其后才是窗口状态、deep-link 和其它系统能力插件。该能力不进入 HostBridge 清单,不向 H5 暴露任意窗口状态读写,也不改变托盘关闭隐藏、单实例唤醒和托盘恢复主窗口的既有语义。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user