6066a7be4f
桌面壳生命周期事件失败只记录固定阶段标签 扩展桌面壳配置门禁禁止生命周期日志输出 Tauri 错误细节 补充宿主壳方案和共享决策中的生命周期诊断边界
244 lines
6.6 KiB
Rust
244 lines
6.6 KiB
Rust
use crate::shell::events::host_bridge_event_script;
|
|
use crate::shell::navigation::register_desktop_navigation_events;
|
|
use serde_json::json;
|
|
use tauri::webview::PageLoadEvent;
|
|
use tauri::{WebviewWindow, WindowEvent};
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) struct DesktopLifecyclePayload {
|
|
state: &'static str,
|
|
focused: bool,
|
|
native_state: &'static str,
|
|
}
|
|
|
|
pub(crate) fn resolve_desktop_lifecycle_payload(
|
|
focused: bool,
|
|
visible: bool,
|
|
minimized: bool,
|
|
) -> DesktopLifecyclePayload {
|
|
if !visible {
|
|
return DesktopLifecyclePayload {
|
|
state: "background",
|
|
focused: false,
|
|
native_state: "hidden",
|
|
};
|
|
}
|
|
|
|
if minimized {
|
|
return DesktopLifecyclePayload {
|
|
state: "background",
|
|
focused: false,
|
|
native_state: "minimized",
|
|
};
|
|
}
|
|
|
|
if focused {
|
|
DesktopLifecyclePayload {
|
|
state: "active",
|
|
focused: true,
|
|
native_state: "focused",
|
|
}
|
|
} else {
|
|
DesktopLifecyclePayload {
|
|
state: "inactive",
|
|
focused: false,
|
|
native_state: "blurred",
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn emit_desktop_lifecycle_event(
|
|
window: &WebviewWindow,
|
|
state: &'static str,
|
|
focused: bool,
|
|
native_state: &'static str,
|
|
) -> tauri::Result<()> {
|
|
let script = host_bridge_event_script(
|
|
"app.lifecycle",
|
|
json!({
|
|
"state": state,
|
|
"focused": focused,
|
|
"nativeState": native_state,
|
|
}),
|
|
)
|
|
.map_err(tauri::Error::Json)?;
|
|
|
|
window.eval(script)
|
|
}
|
|
|
|
pub(crate) fn emit_desktop_lifecycle_payload(
|
|
window: &WebviewWindow,
|
|
payload: DesktopLifecyclePayload,
|
|
) -> tauri::Result<()> {
|
|
emit_desktop_lifecycle_event(window, payload.state, payload.focused, payload.native_state)
|
|
}
|
|
|
|
fn resolve_desktop_lifecycle_window_flag(
|
|
label: &'static str,
|
|
result: tauri::Result<bool>,
|
|
default_value: bool,
|
|
) -> bool {
|
|
match result {
|
|
Ok(value) => value,
|
|
Err(_error) => {
|
|
eprintln!("desktop host event failed for app.lifecycle.{label}");
|
|
default_value
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn emit_current_desktop_lifecycle_event(window: &WebviewWindow) -> tauri::Result<()> {
|
|
let visible =
|
|
resolve_desktop_lifecycle_window_flag("visible", window.is_visible(), true);
|
|
let minimized =
|
|
resolve_desktop_lifecycle_window_flag("minimized", window.is_minimized(), false);
|
|
let focused = resolve_desktop_lifecycle_window_flag(
|
|
"focused",
|
|
window.is_focused(),
|
|
visible && !minimized,
|
|
);
|
|
emit_desktop_lifecycle_payload(
|
|
window,
|
|
resolve_desktop_lifecycle_payload(focused, visible, minimized),
|
|
)
|
|
}
|
|
|
|
pub(crate) fn register_desktop_lifecycle_events(window: &WebviewWindow) {
|
|
let lifecycle_window = window.clone();
|
|
window.on_window_event(move |event| {
|
|
if matches!(event, WindowEvent::Focused(_) | WindowEvent::Resized(_)) {
|
|
log_desktop_host_event_result(
|
|
"app.lifecycle",
|
|
emit_current_desktop_lifecycle_event(&lifecycle_window),
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
pub(crate) fn should_replay_desktop_webview_state_on_page_load(event: PageLoadEvent) -> bool {
|
|
event == PageLoadEvent::Finished
|
|
}
|
|
|
|
pub(crate) fn log_desktop_host_event_result(
|
|
label: &'static str,
|
|
result: tauri::Result<()>,
|
|
) -> bool {
|
|
match result {
|
|
Ok(()) => true,
|
|
Err(_error) => {
|
|
eprintln!("desktop host event failed for {label}");
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn replay_desktop_webview_state(window: &WebviewWindow) {
|
|
log_desktop_host_event_result(
|
|
"app.lifecycle",
|
|
emit_current_desktop_lifecycle_event(window),
|
|
);
|
|
log_desktop_host_event_result(
|
|
"navigation.canGoBack",
|
|
register_desktop_navigation_events(window),
|
|
);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn desktop_page_load_replays_state_only_after_finished_load() {
|
|
assert!(should_replay_desktop_webview_state_on_page_load(
|
|
PageLoadEvent::Finished
|
|
));
|
|
assert!(!should_replay_desktop_webview_state_on_page_load(
|
|
PageLoadEvent::Started
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn desktop_host_event_result_reports_success_and_failure() {
|
|
assert!(log_desktop_host_event_result("network", Ok(())));
|
|
assert!(!log_desktop_host_event_result(
|
|
"navigation",
|
|
Err(tauri::Error::AssetNotFound("navigation".to_string()))
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn desktop_host_event_result_logs_stable_label_only() {
|
|
assert!(!log_desktop_host_event_result(
|
|
"navigation.canGoBack",
|
|
Err(tauri::Error::AssetNotFound(
|
|
"navigation?token=private".to_string()
|
|
))
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn desktop_lifecycle_window_flag_logs_failure_and_uses_default() {
|
|
assert!(resolve_desktop_lifecycle_window_flag(
|
|
"visible",
|
|
Ok(true),
|
|
false
|
|
));
|
|
assert!(!resolve_desktop_lifecycle_window_flag(
|
|
"focused",
|
|
Err(tauri::Error::WindowNotFound),
|
|
false
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn desktop_lifecycle_window_flag_logs_stable_label_only() {
|
|
assert!(!resolve_desktop_lifecycle_window_flag(
|
|
"focused",
|
|
Err(tauri::Error::AssetNotFound(
|
|
"window?token=private".to_string()
|
|
)),
|
|
false
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn desktop_lifecycle_payload_maps_hidden_and_minimized_to_background() {
|
|
assert_eq!(
|
|
resolve_desktop_lifecycle_payload(true, false, false),
|
|
DesktopLifecyclePayload {
|
|
state: "background",
|
|
focused: false,
|
|
native_state: "hidden",
|
|
}
|
|
);
|
|
assert_eq!(
|
|
resolve_desktop_lifecycle_payload(true, true, true),
|
|
DesktopLifecyclePayload {
|
|
state: "background",
|
|
focused: false,
|
|
native_state: "minimized",
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn desktop_lifecycle_payload_maps_visible_focus_state() {
|
|
assert_eq!(
|
|
resolve_desktop_lifecycle_payload(true, true, false),
|
|
DesktopLifecyclePayload {
|
|
state: "active",
|
|
focused: true,
|
|
native_state: "focused",
|
|
}
|
|
);
|
|
assert_eq!(
|
|
resolve_desktop_lifecycle_payload(false, true, false),
|
|
DesktopLifecyclePayload {
|
|
state: "inactive",
|
|
focused: false,
|
|
native_state: "blurred",
|
|
}
|
|
);
|
|
}
|
|
}
|