桌面壳接入应用菜单
新增 Tauri 应用菜单并复用显示、刷新和退出窗口动作 收紧桌面壳菜单模块和结构门禁 同步宿主壳方案文档和团队决策记录
This commit is contained in:
@@ -1079,6 +1079,7 @@ const requiredRustHostModules = [
|
||||
'shell/events.rs',
|
||||
'shell/file_drop.rs',
|
||||
'shell/lifecycle.rs',
|
||||
'shell/menu.rs',
|
||||
'shell/mod.rs',
|
||||
'shell/navigation.rs',
|
||||
'shell/network.rs',
|
||||
@@ -1104,6 +1105,15 @@ const requiredRustHostSnippets = [
|
||||
'DESKTOP_DEEP_LINK_HOSTS',
|
||||
'resolve_desktop_single_instance_action',
|
||||
'tauri_plugin_clipboard_manager::init()',
|
||||
'register_desktop_app_menu(app)?',
|
||||
'DESKTOP_APP_MENU_SHOW',
|
||||
'DESKTOP_APP_MENU_RELOAD',
|
||||
'DESKTOP_APP_MENU_QUIT',
|
||||
'resolve_desktop_app_menu_action',
|
||||
'app.set_menu',
|
||||
'app.on_menu_event',
|
||||
'Submenu::with_items',
|
||||
'PredefinedMenuItem::copy',
|
||||
'TrayIconBuilder::with_id',
|
||||
'register_desktop_tray(app)',
|
||||
'DESKTOP_TRAY_ID',
|
||||
|
||||
@@ -3,6 +3,7 @@ mod shell;
|
||||
|
||||
use host_bridge::{host_bridge_request, DesktopShareState, HostBridgeReplayState};
|
||||
use shell::deep_link::{register_desktop_deep_link_events, register_desktop_deep_link_schemes};
|
||||
use shell::menu::register_desktop_app_menu;
|
||||
use shell::tray::{
|
||||
register_desktop_tray, register_desktop_window_close_events,
|
||||
resolve_desktop_single_instance_action, show_main_window, DesktopSingleInstanceAction,
|
||||
@@ -35,6 +36,7 @@ fn main() {
|
||||
.plugin(tauri_plugin_notification::init())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.setup(|app| {
|
||||
register_desktop_app_menu(app)?;
|
||||
let tray_registered = match register_desktop_tray(app) {
|
||||
Ok(()) => true,
|
||||
Err(error) => {
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
use crate::shell::tray::{reload_main_window, show_main_window};
|
||||
use tauri::menu::{Menu, MenuItem, PredefinedMenuItem, Submenu};
|
||||
|
||||
pub(crate) const DESKTOP_APP_MENU_SHOW: &str = "app-menu-show-main-window";
|
||||
pub(crate) const DESKTOP_APP_MENU_RELOAD: &str = "app-menu-reload-main-window";
|
||||
pub(crate) const DESKTOP_APP_MENU_QUIT: &str = "app-menu-quit-desktop-shell";
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(crate) enum DesktopAppMenuAction {
|
||||
ShowMainWindow,
|
||||
ReloadMainWindow,
|
||||
QuitApp,
|
||||
Ignore,
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_desktop_app_menu_action(menu_id: &str) -> DesktopAppMenuAction {
|
||||
match menu_id {
|
||||
DESKTOP_APP_MENU_SHOW => DesktopAppMenuAction::ShowMainWindow,
|
||||
DESKTOP_APP_MENU_RELOAD => DesktopAppMenuAction::ReloadMainWindow,
|
||||
DESKTOP_APP_MENU_QUIT => DesktopAppMenuAction::QuitApp,
|
||||
_ => DesktopAppMenuAction::Ignore,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_desktop_app_menu_action(app: &tauri::AppHandle, action: DesktopAppMenuAction) {
|
||||
match action {
|
||||
DesktopAppMenuAction::ShowMainWindow => {
|
||||
let _ = show_main_window(app);
|
||||
}
|
||||
DesktopAppMenuAction::ReloadMainWindow => {
|
||||
let _ = reload_main_window(app);
|
||||
}
|
||||
DesktopAppMenuAction::QuitApp => app.exit(0),
|
||||
DesktopAppMenuAction::Ignore => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn register_desktop_app_menu(app: &tauri::App) -> tauri::Result<()> {
|
||||
let show_item =
|
||||
MenuItem::with_id(app, DESKTOP_APP_MENU_SHOW, "显示主窗口", true, None::<&str>)?;
|
||||
let reload_item = MenuItem::with_id(
|
||||
app,
|
||||
DESKTOP_APP_MENU_RELOAD,
|
||||
"刷新",
|
||||
true,
|
||||
Some("CmdOrCtrl+R"),
|
||||
)?;
|
||||
let quit_item = MenuItem::with_id(
|
||||
app,
|
||||
DESKTOP_APP_MENU_QUIT,
|
||||
"退出",
|
||||
true,
|
||||
Some("CmdOrCtrl+Q"),
|
||||
)?;
|
||||
let app_separator = PredefinedMenuItem::separator(app)?;
|
||||
let app_menu = Submenu::with_items(
|
||||
app,
|
||||
"Genarrative",
|
||||
true,
|
||||
&[&show_item, &reload_item, &app_separator, &quit_item],
|
||||
)?;
|
||||
|
||||
let undo_item = PredefinedMenuItem::undo(app, Some("撤销"))?;
|
||||
let redo_item = PredefinedMenuItem::redo(app, Some("重做"))?;
|
||||
let edit_separator = PredefinedMenuItem::separator(app)?;
|
||||
let cut_item = PredefinedMenuItem::cut(app, Some("剪切"))?;
|
||||
let copy_item = PredefinedMenuItem::copy(app, Some("复制"))?;
|
||||
let paste_item = PredefinedMenuItem::paste(app, Some("粘贴"))?;
|
||||
let select_all_item = PredefinedMenuItem::select_all(app, Some("全选"))?;
|
||||
let edit_menu = Submenu::with_items(
|
||||
app,
|
||||
"编辑",
|
||||
true,
|
||||
&[
|
||||
&undo_item,
|
||||
&redo_item,
|
||||
&edit_separator,
|
||||
&cut_item,
|
||||
©_item,
|
||||
&paste_item,
|
||||
&select_all_item,
|
||||
],
|
||||
)?;
|
||||
|
||||
let minimize_item = PredefinedMenuItem::minimize(app, Some("最小化"))?;
|
||||
let maximize_item = PredefinedMenuItem::maximize(app, Some("最大化"))?;
|
||||
let window_separator = PredefinedMenuItem::separator(app)?;
|
||||
let close_item = PredefinedMenuItem::close_window(app, Some("关闭窗口"))?;
|
||||
let window_menu = Submenu::with_items(
|
||||
app,
|
||||
"窗口",
|
||||
true,
|
||||
&[
|
||||
&minimize_item,
|
||||
&maximize_item,
|
||||
&window_separator,
|
||||
&close_item,
|
||||
],
|
||||
)?;
|
||||
|
||||
app.set_menu(Menu::with_items(
|
||||
app,
|
||||
&[&app_menu, &edit_menu, &window_menu],
|
||||
)?)?;
|
||||
app.on_menu_event(|app, event| {
|
||||
let menu_id = event.id().0.as_str();
|
||||
handle_desktop_app_menu_action(app, resolve_desktop_app_menu_action(menu_id));
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn desktop_app_menu_ids_map_to_window_actions() {
|
||||
assert_eq!(
|
||||
resolve_desktop_app_menu_action(DESKTOP_APP_MENU_SHOW),
|
||||
DesktopAppMenuAction::ShowMainWindow
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_desktop_app_menu_action(DESKTOP_APP_MENU_RELOAD),
|
||||
DesktopAppMenuAction::ReloadMainWindow
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_desktop_app_menu_action(DESKTOP_APP_MENU_QUIT),
|
||||
DesktopAppMenuAction::QuitApp
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_desktop_app_menu_action("unknown"),
|
||||
DesktopAppMenuAction::Ignore
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ pub(crate) mod deep_link;
|
||||
mod events;
|
||||
mod file_drop;
|
||||
mod lifecycle;
|
||||
pub(crate) mod menu;
|
||||
mod navigation;
|
||||
mod network;
|
||||
mod runtime;
|
||||
|
||||
@@ -68,7 +68,7 @@ pub(crate) fn show_main_window(app: &tauri::AppHandle) -> tauri::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reload_main_window(app: &tauri::AppHandle) -> tauri::Result<()> {
|
||||
pub(crate) fn reload_main_window(app: &tauri::AppHandle) -> tauri::Result<()> {
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
window.reload()?;
|
||||
}
|
||||
|
||||
@@ -2499,3 +2499,10 @@
|
||||
- 决策:桌面壳接入 `tauri-plugin-window-state`,并把插件配置收口到 `apps/desktop-shell/src-tauri/src/shell/window_state.rs`。只保存 `SIZE`、`POSITION` 和 `MAXIMIZED`,不保存 `VISIBLE`、`FULLSCREEN` 或 `DECORATIONS`;该能力属于宿主壳自身体验,不进入 HostBridge capability,不暴露窗口状态插件 command 给 H5。插件注册顺序固定为 single-instance 优先,其后才是 window-state、deep-link 和其它系统插件。
|
||||
- 影响范围:`apps/desktop-shell/src-tauri/Cargo.toml`、`apps/desktop-shell/src-tauri/Cargo.lock`、`apps/desktop-shell/src-tauri/src/main.rs`、`apps/desktop-shell/src-tauri/src/shell/window_state.rs`、`apps/desktop-shell/scripts/check-config.mjs`、Expo / Tauri HostBridge 方案文档。
|
||||
- 验证方式:`npm run desktop-shell:typecheck`、`npm run desktop-shell:test`、`npm run desktop-shell:build -- --no-bundle`、`npm run check:native-shells`、`npm run typecheck -- --pretty false`、`npm run check:encoding`、`git diff --check`。
|
||||
|
||||
## 2026-06-18 桌面壳应用菜单
|
||||
|
||||
- 背景:桌面壳方案要求 Tauri 承接系统菜单,但当前桌面壳只有系统托盘菜单和 HostBridge 受控能力;可分发桌面包缺少常规应用菜单会让刷新、退出、系统编辑和窗口操作只能依赖 WebView 或托盘。
|
||||
- 决策:新增 `apps/desktop-shell/src-tauri/src/shell/menu.rs` 注册 Tauri 应用菜单。应用菜单只复用宿主壳级显示主窗口、刷新主窗口和退出应用动作;编辑菜单和窗口菜单使用 Tauri 原生预定义项承接剪切、复制、粘贴、全选、最小化、最大化和关闭窗口。该能力不进入 HostBridge capability,不开放菜单 API、shell API 或任意窗口控制给 H5;菜单注册失败直接阻断启动,避免生产桌面壳缺少系统菜单仍静默运行。
|
||||
- 影响范围:`apps/desktop-shell/src-tauri/src/main.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`、`scripts/check-native-shells.mjs`、Expo / Tauri HostBridge 方案文档。
|
||||
- 验证方式:`npm run desktop-shell:typecheck`、`npm run desktop-shell:test`、`npm run desktop-shell:build -- --no-bundle`、`npm run check:native-shells`、`npm run typecheck -- --pretty false`、`npm run check:encoding`、`git diff --check`。
|
||||
|
||||
@@ -64,7 +64,7 @@ src/
|
||||
|
||||
已落地:`packages/shared/src/contracts/hostBridge.ts` 保存消息 envelope、method、payload 和错误码,H5、Expo 壳与 Tauri 壳共享同一份协议类型。
|
||||
|
||||
三端宿主桥接层按职责对齐命名:微信小程序页面路由仍保留在 `miniprogram/pages/*`,`miniprogram/host-bridge/protocol.js` 只沉淀微信壳能力、页面 URL、结果 hash / storage key 和分享消息类型等常量,`dispatch.js` 只作为 `protocol`、`webView`、`payment`、`shareGrid`、`subscribeMessage` 的薄索引,真实协议归一、支付 / 订阅 / 分享结果编解码仍分别在 `webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,不把微信小程序硬改成 Expo / Tauri 的 request 总线;Page 生命周期、`wx.*` 容器调用、WebView 容器行为和页面工厂统一放在 `miniprogram/shell/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,页面入口只做 `Page(createWechat...Page())` 装配。Expo 移动壳使用 `apps/mobile-shell/src/host-bridge/protocol.ts` 承接 envelope、request 校验、ok / failure 响应和 replay 基础类型,`capabilities.ts` 承接能力清单与 iOS 差异能力,`dispatch.ts` 承接 method 分发和宿主能力调用,`files.ts` / `share.ts` 分别承接文件和分享能力,`bridge.ts` 只作为 WebView message 入口、request id replay 编排和对外 facade;`apps/mobile-shell/App.tsx` 只装配 `apps/mobile-shell/src/shell/ShellApp.tsx`,由 `apps/mobile-shell/src/shell/*.ts(x)` 承接 WebView 容器、URL、导航、网络、生命周期、安全区和 WebView policy。Tauri 桌面壳使用 `apps/desktop-shell/src-tauri/src/host_bridge/protocol.rs` 承接 envelope、method 白名单、request 校验和 replay 状态,`capabilities.rs` 承接能力清单,`dispatch.rs` 承接 method 分发和宿主能力调用,`files.rs` / `share.rs` 分别承接文件和分享能力,`mod.rs` 只保留模块声明、必要 re-export、`host_bridge_request` command facade 和 replay 编排;`apps/desktop-shell/src-tauri/src/shell/runtime.rs`、`url.rs`、`navigation.rs`、`network.rs`、`lifecycle.rs`、`file_drop.rs`、`events.rs`、`deep_link.rs`、`tray.rs`、`window_state.rs` 和 `webview.rs` 分别承接运行态、入口 URL、导航 / 下载、网络、生命周期、拖拽图片、HostBridge 事件注入、深链、托盘、窗口状态持久化和 WebView 门面,`main.rs` 只保留 Tauri builder / plugin / window 装配。
|
||||
三端宿主桥接层按职责对齐命名:微信小程序页面路由仍保留在 `miniprogram/pages/*`,`miniprogram/host-bridge/protocol.js` 只沉淀微信壳能力、页面 URL、结果 hash / storage key 和分享消息类型等常量,`dispatch.js` 只作为 `protocol`、`webView`、`payment`、`shareGrid`、`subscribeMessage` 的薄索引,真实协议归一、支付 / 订阅 / 分享结果编解码仍分别在 `webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,不把微信小程序硬改成 Expo / Tauri 的 request 总线;Page 生命周期、`wx.*` 容器调用、WebView 容器行为和页面工厂统一放在 `miniprogram/shell/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,页面入口只做 `Page(createWechat...Page())` 装配。Expo 移动壳使用 `apps/mobile-shell/src/host-bridge/protocol.ts` 承接 envelope、request 校验、ok / failure 响应和 replay 基础类型,`capabilities.ts` 承接能力清单与 iOS 差异能力,`dispatch.ts` 承接 method 分发和宿主能力调用,`files.ts` / `share.ts` 分别承接文件和分享能力,`bridge.ts` 只作为 WebView message 入口、request id replay 编排和对外 facade;`apps/mobile-shell/App.tsx` 只装配 `apps/mobile-shell/src/shell/ShellApp.tsx`,由 `apps/mobile-shell/src/shell/*.ts(x)` 承接 WebView 容器、URL、导航、网络、生命周期、安全区和 WebView policy。Tauri 桌面壳使用 `apps/desktop-shell/src-tauri/src/host_bridge/protocol.rs` 承接 envelope、method 白名单、request 校验和 replay 状态,`capabilities.rs` 承接能力清单,`dispatch.rs` 承接 method 分发和宿主能力调用,`files.rs` / `share.rs` 分别承接文件和分享能力,`mod.rs` 只保留模块声明、必要 re-export、`host_bridge_request` command facade 和 replay 编排;`apps/desktop-shell/src-tauri/src/shell/runtime.rs`、`url.rs`、`navigation.rs`、`network.rs`、`lifecycle.rs`、`file_drop.rs`、`events.rs`、`deep_link.rs`、`tray.rs`、`menu.rs`、`window_state.rs` 和 `webview.rs` 分别承接运行态、入口 URL、导航 / 下载、网络、生命周期、拖拽图片、HostBridge 事件注入、深链、托盘、应用菜单、窗口状态持久化和 WebView 门面,`main.rs` 只保留 Tauri builder / plugin / window 装配。
|
||||
|
||||
## HostBridge 消息协议
|
||||
|
||||
@@ -183,7 +183,7 @@ Tauri 壳同样只负责桌面宿主能力,不承接玩法业务。
|
||||
- Rust 侧只暴露一个受控 `host_bridge_request` command,再在 Rust 内部按 method 白名单分发。
|
||||
- Tauri capabilities 只授予主窗口所需命令;默认不开放文件系统、shell、全局剪贴板或任意插件能力。
|
||||
- 桌面支付首期走现有 H5 / 二维码 / 外部浏览器路径,不在 Rust 侧保存支付凭据。
|
||||
- 文件导出、作品卡保存、图片拖拽导入、系统托盘、自动更新等桌面能力按后续需求逐项开放;其中系统托盘属于桌面壳自有能力,不作为 HostBridge method 暴露给 H5。
|
||||
- 文件导出、作品卡保存、图片拖拽导入、应用菜单、系统托盘、自动更新等桌面能力按后续需求逐项开放;其中应用菜单和系统托盘属于桌面壳自有能力,不作为 HostBridge method 暴露给 H5。
|
||||
- 主 WebView 默认拒绝网页自动下载或 `<a download>` 触发的落盘动作;用户保存文本、图片、音频等内容必须走已声明的 `file.exportText`、`file.exportImage`、`file.exportAudio` HostBridge method,由 Rust 侧执行 MIME、大小、文件名清洗和系统保存对话框确认。
|
||||
- 主 WebView 显式关闭 DevTools,Cargo 不启用 Tauri `devtools` feature;本地调试通过普通浏览器和 Vite 完成,不把可分发桌面壳变成调试容器。
|
||||
- 崩溃上报、前端 analytics、桌面遥测日志、自动更新和渠道分发 SDK 都必须等真实端点、采集字段、用户同意、隐私策略、签名和发布流程确定后逐项接入;当前桌面壳不安装 Sentry、Datadog、PostHog、Segment、Amplitude、Bugsnag、OpenTelemetry、Tauri log / updater 等相关依赖。
|
||||
@@ -350,6 +350,8 @@ GameBridge 禁止:
|
||||
|
||||
2026-06-18 追加:桌面壳启用 Tauri 真实系统托盘,并复用品牌图标。托盘菜单只提供宿主壳级动作:显示主窗口、刷新主窗口和退出应用;左键点击托盘图标恢复并聚焦主窗口。该能力不进入 HostBridge capability 清单,不向 H5 暴露托盘 API、菜单 API、shell API 或任意窗口控制;如果当前桌面环境无法注册托盘,壳会继续启动主窗口。托盘注册成功时,用户点击主窗口关闭按钮会隐藏到托盘,必须通过托盘“退出”动作结束应用;托盘注册失败时不拦截关闭,避免窗口消失后没有恢复入口。
|
||||
|
||||
2026-06-18 追加:桌面壳启用 Tauri 应用菜单。`shell/menu.rs` 注册应用菜单、编辑菜单和窗口菜单,其中应用菜单只复用宿主壳级动作:显示主窗口、刷新主窗口和退出应用;编辑 / 窗口项使用 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 窗口状态持久化。`shell/window_state.rs` 只配置 `tauri-plugin-window-state` 保存主窗口大小、位置和最大化状态,并排除可见性、全屏和装饰状态;插件注册顺序固定为 single-instance 优先,其后才是窗口状态、deep-link 和其它系统能力插件。该能力不进入 HostBridge 清单,不向 H5 暴露任意窗口状态读写,也不改变托盘关闭隐藏、单实例唤醒和托盘恢复主窗口的既有语义。
|
||||
@@ -418,7 +420,7 @@ GameBridge 禁止:
|
||||
|
||||
2026-06-18 追加:移动壳 HostBridge 消息入口增加来源校验。`onMessage` 不只依赖导航拦截和 `originWhitelist`,还会读取 `event.nativeEvent.url`,只有同源主站页面才能进入 `handleMobileHostBridgeMessage`;`about:blank`、外域 URL、协议降级或危险协议页面发来的消息全部丢弃,不返回 HostBridge 错误细节。该校验与 `navigation.openNativePage` 共用同源规则,防止历史中间页或异常页面在带完整 HostBridge 的 WebView 中发起宿主能力请求。
|
||||
|
||||
2026-06-18 追加:微信、移动端和桌面端桥接层文件结构按职责对齐。微信小程序的 `web-view`、支付、九宫切图和订阅消息桥接逻辑统一迁入 `miniprogram/host-bridge/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,页面目录只保留页面生命周期、WXML/WXSS 和装配;移动壳拆成 `apps/mobile-shell/src/host-bridge/protocol.ts`、`files.ts`、`share.ts` 和 facade `bridge.ts`,与桌面端 `host_bridge/protocol.rs`、`files.rs`、`share.rs`、`mod.rs` 对齐;移动壳根 `App.tsx` 也保持薄入口,只装配 `src/shell/ShellApp.tsx`,WebView 容器、深链、网络、生命周期和安全策略全部留在 `src/shell/`;桌面壳 Rust 源码拆成 `apps/desktop-shell/src-tauri/src/host_bridge/*.rs` 与 `apps/desktop-shell/src-tauri/src/shell/*.rs`,其中 `runtime.rs`、`url.rs`、`navigation.rs`、`network.rs`、`lifecycle.rs`、`file_drop.rs`、`events.rs`、`deep_link.rs`、`tray.rs`、`window_state.rs` 和 `webview.rs` 分别承接运行态、入口 URL、导航 / 下载、网络、生命周期、拖拽图片、HostBridge 事件注入、深链、托盘、窗口状态持久化和 WebView 门面,薄 `main.rs` 只声明两个模块并装配 Tauri builder / plugin / window。根级 `npm run check:native-shells` 会锁定三端桥接层目录清单,避免后续把能力逻辑重新散落到页面、移动入口或桌面入口。
|
||||
2026-06-18 追加:微信、移动端和桌面端桥接层文件结构按职责对齐。微信小程序的 `web-view`、支付、九宫切图和订阅消息桥接逻辑统一迁入 `miniprogram/host-bridge/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js`,页面目录只保留页面生命周期、WXML/WXSS 和装配;移动壳拆成 `apps/mobile-shell/src/host-bridge/protocol.ts`、`files.ts`、`share.ts` 和 facade `bridge.ts`,与桌面端 `host_bridge/protocol.rs`、`files.rs`、`share.rs`、`mod.rs` 对齐;移动壳根 `App.tsx` 也保持薄入口,只装配 `src/shell/ShellApp.tsx`,WebView 容器、深链、网络、生命周期和安全策略全部留在 `src/shell/`;桌面壳 Rust 源码拆成 `apps/desktop-shell/src-tauri/src/host_bridge/*.rs` 与 `apps/desktop-shell/src-tauri/src/shell/*.rs`,其中 `runtime.rs`、`url.rs`、`navigation.rs`、`network.rs`、`lifecycle.rs`、`file_drop.rs`、`events.rs`、`deep_link.rs`、`tray.rs`、`menu.rs`、`window_state.rs` 和 `webview.rs` 分别承接运行态、入口 URL、导航 / 下载、网络、生命周期、拖拽图片、HostBridge 事件注入、深链、托盘、应用菜单、窗口状态持久化和 WebView 门面,薄 `main.rs` 只声明两个模块并装配 Tauri builder / plugin / window。根级 `npm run check:native-shells` 会锁定三端桥接层目录清单,避免后续把能力逻辑重新散落到页面、移动入口或桌面入口。
|
||||
|
||||
### Phase 4:宿主能力扩展
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ const expectedDesktopShellRustFiles = [
|
||||
'events.rs',
|
||||
'file_drop.rs',
|
||||
'lifecycle.rs',
|
||||
'menu.rs',
|
||||
'mod.rs',
|
||||
'navigation.rs',
|
||||
'network.rs',
|
||||
|
||||
Reference in New Issue
Block a user