锁定桌面壳单端结构门禁
为桌面壳配置检查增加 Rust 根目录与 host_bridge/shell 模块清单校验 要求 main.rs 保持薄入口并由 app.rs 承接 Tauri 装配 补充共享决策记录说明桌面壳单端结构门禁
This commit is contained in:
@@ -162,6 +162,35 @@ const requiredPngIconSizes = new Map([
|
||||
['128x128@2x.png', 256],
|
||||
['icon.png', 512],
|
||||
]);
|
||||
const expectedDesktopRustRootEntries = [
|
||||
'dir:host_bridge',
|
||||
'dir:shell',
|
||||
'file:app.rs',
|
||||
'file:main.rs',
|
||||
];
|
||||
const expectedDesktopHostBridgeRustFiles = [
|
||||
'capabilities.rs',
|
||||
'dispatch.rs',
|
||||
'files.rs',
|
||||
'mod.rs',
|
||||
'protocol.rs',
|
||||
'share.rs',
|
||||
];
|
||||
const expectedDesktopShellRustFiles = [
|
||||
'deep_link.rs',
|
||||
'events.rs',
|
||||
'file_drop.rs',
|
||||
'lifecycle.rs',
|
||||
'menu.rs',
|
||||
'mod.rs',
|
||||
'navigation.rs',
|
||||
'network.rs',
|
||||
'runtime.rs',
|
||||
'tray.rs',
|
||||
'url.rs',
|
||||
'webview.rs',
|
||||
'window_state.rs',
|
||||
];
|
||||
|
||||
function extractCargoPackageString(source, key) {
|
||||
const match = source.match(new RegExp(`^${key}\\s*=\\s*"([^"]+)"`, 'm'));
|
||||
@@ -479,6 +508,7 @@ assertNoBlockedNpmLockPackages();
|
||||
assertNoBlockedCargoDependencies();
|
||||
assertNoBlockedCargoLockPackages();
|
||||
assertNoBlockedDesktopSdkSnippets();
|
||||
assertDesktopSourceLayout();
|
||||
|
||||
for (const [scriptName, expected] of Object.entries({
|
||||
dev: 'tauri dev',
|
||||
@@ -898,6 +928,46 @@ function readDirectoryFileList(directory, label) {
|
||||
return files.sort();
|
||||
}
|
||||
|
||||
function assertDesktopSourceLayout() {
|
||||
assertSameList(
|
||||
readDirectoryEntryList(rustSourceDir, 'desktop shell Rust root entries'),
|
||||
expectedDesktopRustRootEntries,
|
||||
'desktop shell Rust root entries',
|
||||
);
|
||||
assertSameList(
|
||||
readDirectoryFileList(
|
||||
new URL('../src-tauri/src/host_bridge/', import.meta.url),
|
||||
'desktop host bridge Rust files',
|
||||
),
|
||||
expectedDesktopHostBridgeRustFiles,
|
||||
'desktop host bridge Rust files',
|
||||
);
|
||||
assertSameList(
|
||||
readDirectoryFileList(
|
||||
new URL('../src-tauri/src/shell/', import.meta.url),
|
||||
'desktop shell Rust files',
|
||||
),
|
||||
expectedDesktopShellRustFiles,
|
||||
'desktop shell Rust files',
|
||||
);
|
||||
|
||||
if (!main.includes('mod app;') || !main.includes('app::run();')) {
|
||||
throw new Error('desktop shell main.rs must stay a thin app entrypoint');
|
||||
}
|
||||
if (
|
||||
main.includes('tauri::Builder::default()') ||
|
||||
main.includes('tauri::generate_handler!')
|
||||
) {
|
||||
throw new Error('desktop shell main.rs must not own Tauri app setup');
|
||||
}
|
||||
if (
|
||||
!app.includes('tauri::Builder::default()') ||
|
||||
!app.includes('crate::host_bridge::host_bridge_request')
|
||||
) {
|
||||
throw new Error('desktop shell app.rs must own Tauri app setup');
|
||||
}
|
||||
}
|
||||
|
||||
function extractTauriBuildCommands(source) {
|
||||
const match = source.match(/\.commands\(\s*&\[\s*([^\]]*?)\s*\]\s*\)/);
|
||||
if (!match) {
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
- 2026-06-18 移动壳 WebView 默认下载边界:Expo WebView 内网页自动下载和 `<a download>` 直接落盘默认关闭;壳层注入脚本阻断 download 链接,iOS `onFileDownload` 只丢弃不落盘,Android 包配置通过 `blockedPermissions` 移除外部存储读写、管理外部存储和请求安装包权限。移动端文本、图片、音频保存只能通过 `file.exportText`、`file.exportImage`、`file.exportAudio` 等 HostBridge 受控导出能力进入系统分享 / 保存面板。
|
||||
- 2026-06-18 移动壳 HostBridge 消息来源校验:Expo 移动壳 `onMessage` 必须根据 `event.nativeEvent.url` 校验消息来源,只有同源主站页面能进入 `handleMobileHostBridgeMessage`;`about:blank`、外域、协议降级和危险协议页面消息直接丢弃,不返回宿主能力错误细节。该规则与 WebView 导航留壳规则共用同源判断,配置检查和移动壳导航测试会拒绝移除。
|
||||
- 2026-06-18 三端桥接层目录同构:微信小程序、Expo 移动壳和 Tauri 桌面壳都按 `host-bridge / shell` 两层管理宿主桥接代码。微信 `miniprogram/host-bridge/webView.js`、`payment.js`、`shareGrid.js`、`subscribeMessage.js` 只放协议归一、支付 / 订阅 / 分享结果编解码和可测试桥接函数,`miniprogram/shell/` 下同名职责文件承接 Page 生命周期、`wx.*` 容器调用、WebView 容器行为和页面工厂;页面目录只保留 `Page(createWechat...Page())` 装配。Expo `protocol.ts`、`capabilities.ts`、`dispatch.ts`、`files.ts`、`scanner.ts`、`share.ts` 和 facade `bridge.ts` 分别对齐 Tauri `host_bridge/protocol.rs`、`capabilities.rs`、`dispatch.rs`、`files.rs`、`share.rs`、`mod.rs`,根 `App.tsx` 只装配 `src/shell/ShellApp.tsx`,不直接进口 HostBridge。Tauri `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 门面。`npm run check:native-shells` 会校验微信、移动和桌面三端目录清单,新增宿主能力必须按同一边界落文件和测试。
|
||||
- 2026-06-19 桌面壳单端结构门禁:`apps/desktop-shell/scripts/check-config.mjs` 与根级 `npm run check:native-shells` 同步校验 `src-tauri/src` 根目录、`host_bridge/` 和 `shell/` 的生产模块清单,并要求 `main.rs` 保持薄入口、`app.rs` 承接 Tauri builder / plugin / window 装配。后续新增桌面宿主能力必须先按 HostBridge / shell 职责边界登记文件和测试,不能只靠根门禁或把能力逻辑塞回 `main.rs`。
|
||||
- 影响范围:`src/services/host-bridge/`、未来 `apps/mobile-shell/`、未来 `apps/desktop-shell/`、移动端支付 / 分享 / 深链 / 推送、桌面端系统能力、AI H5 sandbox 的 GameBridge 边界。
|
||||
- 验证方式:普通浏览器、小程序、Expo 壳、Tauri 壳都能返回正确 `getHostRuntime()`;未支持能力能回退 H5;固定玩法在各宿主中读取同一作品数据和运行态 snapshot;AI sandbox 无法直接调用 HostBridge;Tauri release 不允许任意远端页面调用桌面命令。
|
||||
- 关联文档:`docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md`、`docs/【前端架构】宿主壳能力统一协议-2026-06-17.md`。
|
||||
|
||||
Reference in New Issue
Block a user