收口原生网络查询边界
将 Expo 网络状态查询收口到 HostBridge network 模块 将 Tauri 网络状态查询收口到 HostBridge network 模块 同步原生壳结构门禁、架构文档和共享记忆
This commit is contained in:
@@ -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
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user