接入原生壳生命周期事件
新增 app.lifecycle HostBridge 能力与 H5 订阅入口 Expo 壳通过 React Native AppState 注入真实前后台状态 Tauri 壳通过主窗口 focus 和 blur 注入真实激活状态 更新壳能力漂移检查、测试和架构文档
This commit is contained in:
@@ -7,6 +7,8 @@ use std::sync::Mutex;
|
||||
use tauri::Manager;
|
||||
use tauri::Theme;
|
||||
use tauri::Url;
|
||||
use tauri::WebviewWindow;
|
||||
use tauri::WindowEvent;
|
||||
use tauri_plugin_clipboard_manager::ClipboardExt;
|
||||
use tauri_plugin_dialog::DialogExt;
|
||||
use tauri_plugin_opener::OpenerExt;
|
||||
@@ -81,6 +83,7 @@ fn capabilities() -> Vec<&'static str> {
|
||||
vec![
|
||||
"host.getRuntime",
|
||||
"appearance.getColorScheme",
|
||||
"app.lifecycle",
|
||||
"share.open",
|
||||
"share.setTarget",
|
||||
"navigation.openNativePage",
|
||||
@@ -403,6 +406,55 @@ fn write_export_bytes_file(path: PathBuf, bytes: Vec<u8>) -> Result<usize, Strin
|
||||
Ok(byte_count)
|
||||
}
|
||||
|
||||
fn host_bridge_event_script(event: &str, payload: Value) -> Result<String, serde_json::Error> {
|
||||
let message = json!({
|
||||
"bridge": HOST_BRIDGE_PROTOCOL,
|
||||
"version": HOST_BRIDGE_VERSION,
|
||||
"event": event,
|
||||
"payload": payload,
|
||||
});
|
||||
let data = serde_json::to_string(&message)?;
|
||||
let data_literal = serde_json::to_string(&data)?;
|
||||
|
||||
Ok(format!(
|
||||
"window.dispatchEvent(new MessageEvent('message', {{ data: {} }})); true;",
|
||||
data_literal
|
||||
))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fn register_desktop_lifecycle_events(window: &WebviewWindow) {
|
||||
let lifecycle_window = window.clone();
|
||||
window.on_window_event(move |event| {
|
||||
if let WindowEvent::Focused(focused) = event {
|
||||
let (state, native_state) = if *focused {
|
||||
("active", "focused")
|
||||
} else {
|
||||
("inactive", "blurred")
|
||||
};
|
||||
let _ = emit_desktop_lifecycle_event(&lifecycle_window, state, *focused, native_state);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn payload_string<'a>(value: &'a Value, field: &str) -> Option<&'a str> {
|
||||
value
|
||||
.get(field)
|
||||
@@ -727,7 +779,10 @@ fn main() {
|
||||
.setup(|app| {
|
||||
let window_config = app.config().app.windows.get(0).cloned();
|
||||
if let Some(config) = window_config {
|
||||
tauri::WebviewWindowBuilder::from_config(app.handle(), &config)?.build()?;
|
||||
let window =
|
||||
tauri::WebviewWindowBuilder::from_config(app.handle(), &config)?.build()?;
|
||||
register_desktop_lifecycle_events(&window);
|
||||
let _ = emit_desktop_lifecycle_event(&window, "active", true, "created");
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
@@ -763,6 +818,10 @@ mod tests {
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.contains(&json!("appearance.getColorScheme")));
|
||||
assert!(result["capabilities"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.contains(&json!("app.lifecycle")));
|
||||
assert!(result["capabilities"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
@@ -833,6 +892,25 @@ mod tests {
|
||||
assert_eq!(color_scheme_from_theme(Theme::Dark), "dark");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn host_bridge_event_script_dispatches_lifecycle_message() {
|
||||
let script = host_bridge_event_script(
|
||||
"app.lifecycle",
|
||||
json!({
|
||||
"state": "active",
|
||||
"focused": true,
|
||||
"nativeState": "focused",
|
||||
}),
|
||||
)
|
||||
.expect("event script");
|
||||
|
||||
assert!(script.contains("MessageEvent('message'"));
|
||||
assert!(script.contains("GenarrativeHostBridge"));
|
||||
assert!(script.contains("app.lifecycle"));
|
||||
assert!(script.contains("\\\"state\\\":\\\"active\\\""));
|
||||
assert!(script.contains("\\\"focused\\\":true"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn external_url_normalization_allows_only_safe_protocols() {
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user