收口原生网络查询边界

将 Expo 网络状态查询收口到 HostBridge network 模块

将 Tauri 网络状态查询收口到 HostBridge network 模块

同步原生壳结构门禁、架构文档和共享记忆
This commit is contained in:
2026-06-19 22:08:19 +08:00
parent 177c18ddcd
commit c0940bc790
11 changed files with 87 additions and 12 deletions
@@ -94,6 +94,14 @@ const desktopHostBridgeNavigationSource = fs.readFileSync(
desktopHostBridgeNavigationPath,
'utf8',
);
const desktopHostBridgeNetworkPath = new URL(
'../src-tauri/src/host_bridge/network.rs',
import.meta.url,
);
const desktopHostBridgeNetworkSource = fs.readFileSync(
desktopHostBridgeNetworkPath,
'utf8',
);
const desktopHostBridgeNotificationsPath = new URL(
'../src-tauri/src/host_bridge/notifications.rs',
import.meta.url,
@@ -225,6 +233,7 @@ const expectedDesktopHostBridgeRustFiles = [
'files.rs',
'mod.rs',
'navigation.rs',
'network.rs',
'notifications.rs',
'protocol.rs',
'share.rs',
@@ -1692,6 +1701,24 @@ for (const snippet of [
}
}
if (
!desktopHostBridgeDispatchSource.includes(
'resolve_desktop_host_bridge_network_status().await',
) ||
desktopHostBridgeDispatchSource.includes('resolve_desktop_network_status') ||
desktopHostBridgeDispatchSource.includes('spawn_blocking(resolve_desktop_network_status)')
) {
throw new Error('desktop shell network HostBridge method must delegate to network module');
}
for (const snippet of [
'resolve_desktop_host_bridge_network_status',
'spawn_blocking(resolve_desktop_network_status)',
]) {
if (!desktopHostBridgeNetworkSource.includes(snippet)) {
throw new Error(`desktop shell network module is missing ${snippet}`);
}
}
if (config.build?.frontendDist !== '../../../dist') {
throw new Error('desktop shell must package the root H5 dist');
}
@@ -1863,6 +1890,7 @@ const expectedRustHostBridgeFiles = [
'files.rs',
'mod.rs',
'navigation.rs',
'network.rs',
'notifications.rs',
'protocol.rs',
'share.rs',
@@ -11,13 +11,14 @@ use crate::host_bridge::navigation::{
open_desktop_host_bridge_external_url, open_desktop_host_bridge_native_page,
reload_desktop_host_bridge_webview,
};
use crate::host_bridge::network::resolve_desktop_host_bridge_network_status;
use crate::host_bridge::notifications::show_desktop_local_notification;
use crate::host_bridge::protocol::{
failed, ok, required_string_payload, validate_request, HostBridgeRequest, HostBridgeResponse,
HostBridgeRuntime, HOST_BRIDGE_VERSION,
};
use crate::host_bridge::share::{share_text_from_request, DesktopShareState};
use crate::shell::webview::{desktop_platform, resolve_desktop_network_status};
use crate::shell::webview::desktop_platform;
use serde_json::json;
use tauri::Manager;
use tauri_plugin_dialog::DialogExt;
@@ -311,9 +312,7 @@ pub(super) async fn execute_host_bridge_request(
Err(response) => response,
},
"network.status" => {
let network_status =
tauri::async_runtime::spawn_blocking(resolve_desktop_network_status).await;
match network_status {
match resolve_desktop_host_bridge_network_status().await {
Ok(status) => ok(request.id, status),
Err(error) => failed(request.id, "host_error", error.to_string()),
}
@@ -5,6 +5,7 @@ mod clipboard;
mod dispatch;
pub(crate) mod files;
mod navigation;
mod network;
mod notifications;
pub(crate) mod protocol;
mod share;
@@ -0,0 +1,8 @@
use crate::shell::webview::resolve_desktop_network_status;
use serde_json::Value;
pub(crate) async fn resolve_desktop_host_bridge_network_status() -> Result<Value, String> {
tauri::async_runtime::spawn_blocking(resolve_desktop_network_status)
.await
.map_err(|error| error.to_string())
}
@@ -30,6 +30,14 @@ const hostBridgeNavigationSource = fs.readFileSync(
hostBridgeNavigationPath,
'utf8',
);
const hostBridgeNetworkPath = new URL(
'../src/host-bridge/network.ts',
import.meta.url,
);
const hostBridgeNetworkSource = fs.readFileSync(
hostBridgeNetworkPath,
'utf8',
);
const notificationsPath = new URL('../src/host-bridge/notifications.ts', import.meta.url);
const notificationsSource = fs.readFileSync(notificationsPath, 'utf8');
const protocolPath = new URL('../src/host-bridge/protocol.ts', import.meta.url);
@@ -96,6 +104,7 @@ const requiredMobileShellSourceModules = [
'host-bridge/files.ts',
'host-bridge/haptics.ts',
'host-bridge/navigation.ts',
'host-bridge/network.ts',
'host-bridge/notifications.ts',
'host-bridge/protocol.ts',
'host-bridge/scanner.ts',
@@ -1897,6 +1906,22 @@ if (!hostBridgeNavigationSource.includes('openMobileShellExternalNavigation(navi
);
}
if (
!dispatchSource.includes('getMobileHostBridgeNetworkStatus()') ||
dispatchSource.includes('../shell/network') ||
dispatchSource.includes('getMobileNetworkStatus()')
) {
throw new Error('mobile shell network HostBridge method must delegate to network module');
}
for (const snippet of [
'getMobileHostBridgeNetworkStatus',
'getMobileNetworkStatus()',
]) {
if (!hostBridgeNetworkSource.includes(snippet)) {
throw new Error(`mobile shell network module is missing ${snippet}`);
}
}
if (!shellAppSource.includes('openMobileShellExternalNavigation(Linking, request.url)')) {
throw new Error(
'mobile shell WebView external navigation must use the tested external navigation helper',
@@ -8,7 +8,6 @@ import {
type HostBridgeRequest,
normalizeHostBridgeLocalNotification,
} from '../../../../packages/shared/src/contracts/hostBridge';
import { getMobileNetworkStatus } from '../shell/network';
import { MOBILE_SHELL_HOST_VERSION } from '../shell/runtime';
import { resolveMobileHostCapabilities } from './capabilities';
import {
@@ -43,6 +42,7 @@ import {
openMobileHostBridgeNativePage,
reloadMobileHostBridgeWebView,
} from './navigation';
import { getMobileHostBridgeNetworkStatus } from './network';
let currentShareTarget: unknown = null;
let navigation: MobileHostBridgeNavigation | null = null;
@@ -117,7 +117,7 @@ export async function dispatchMobileHostBridgeRequest(
case 'app.reloadWebView':
return ok(request, reloadMobileHostBridgeWebView(navigation));
case 'network.status':
return ok(request, await getMobileNetworkStatus());
return ok(request, await getMobileHostBridgeNetworkStatus());
case 'clipboard.writeText':
return ok(request, await writeClipboard(request.payload));
case 'clipboard.readText':
@@ -0,0 +1,5 @@
import { getMobileNetworkStatus } from '../shell/network';
export function getMobileHostBridgeNetworkStatus() {
return getMobileNetworkStatus();
}
@@ -2792,3 +2792,10 @@
- 决策:Expo 移动壳新增 `apps/mobile-shell/src/host-bridge/navigation.ts`,统一承接 HostBridge 外链打开、受控 H5 跳转和 WebView 刷新,底层继续复用 `src/shell/navigation.ts``src/shell/url.ts`Tauri 桌面壳新增 `apps/desktop-shell/src-tauri/src/host_bridge/navigation.rs`,统一承接外链打开、同源 H5 跳转和主窗口刷新,底层继续复用 `shell::navigation` 的 URL 归一和宿主上下文补写。两端 `dispatch` 只保留 method 委托和响应包装,配置检查会拒绝分发层直接调用外链 opener、URL 归一或 WebView navigate / reload 细节。
- 影响范围:`apps/mobile-shell/src/host-bridge/navigation.ts``apps/mobile-shell/src/host-bridge/dispatch.ts``apps/mobile-shell/scripts/check-config.mjs``apps/desktop-shell/src-tauri/src/host_bridge/navigation.rs``apps/desktop-shell/src-tauri/src/host_bridge/dispatch.rs``apps/desktop-shell/scripts/check-config.mjs``scripts/check-native-shells.mjs`、宿主壳能力统一协议文档、Expo / Tauri HostBridge 方案文档。
- 验证方式:`npm run mobile-shell:typecheck``npm run mobile-shell:test -- src/host-bridge/bridge.test.ts``npm run desktop-shell:typecheck``cargo test --manifest-path apps/desktop-shell/src-tauri/Cargo.toml``npm run check:native-shells``npm run check:encoding``git diff --check`
## 2026-06-19 原生壳网络查询桥接边界
- 背景:`network.status` 已由 Expo shell network 和 Tauri shell network 承接真实系统 / 主站可达性查询,但两端 HostBridge `dispatch` 仍直接调用底层 network helper 或异步阻塞包装,继续补壳能力时容易让分发层重新承接宿主细节。
- 决策:Expo 移动壳新增 `apps/mobile-shell/src/host-bridge/network.ts`,统一承接 `network.status` HostBridge 查询并复用 `src/shell/network.ts`Tauri 桌面壳新增 `apps/desktop-shell/src-tauri/src/host_bridge/network.rs`,统一承接 `network.status` HostBridge 查询并复用 `shell::network::resolve_desktop_network_status`。两端 `dispatch` 只保留 method 委托和响应包装,配置检查会拒绝分发层直接导入 shell network 或直接执行 `resolve_desktop_network_status`
- 影响范围:`apps/mobile-shell/src/host-bridge/network.ts``apps/mobile-shell/src/host-bridge/dispatch.ts``apps/mobile-shell/scripts/check-config.mjs``apps/desktop-shell/src-tauri/src/host_bridge/network.rs``apps/desktop-shell/src-tauri/src/host_bridge/dispatch.rs``apps/desktop-shell/scripts/check-config.mjs``scripts/check-native-shells.mjs`、宿主壳能力统一协议文档、Expo / Tauri HostBridge 方案文档。
- 验证方式:`npm run mobile-shell:typecheck``npm run mobile-shell:test -- src/host-bridge/bridge.test.ts``npm run desktop-shell:typecheck``cargo test --manifest-path apps/desktop-shell/src-tauri/Cargo.toml``npm run check:native-shells``npm run check:encoding``git diff --check`
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2
View File
@@ -259,6 +259,7 @@ const expectedMobileHostBridgeFiles = [
'files.ts',
'haptics.ts',
'navigation.ts',
'network.ts',
'notifications.ts',
'protocol.ts',
'scanner.ts',
@@ -303,6 +304,7 @@ const expectedDesktopHostBridgeRustFiles = [
'files.rs',
'mod.rs',
'navigation.rs',
'network.rs',
'notifications.rs',
'protocol.rs',
'share.rs',