收口宿主事件白名单

新增共享 HostBridge event 白名单与类型守卫

让 H5、Expo 和 Tauri 只分发白名单宿主事件

补齐移动端、桌面端和根级原生壳门禁

更新宿主壳方案文档和项目决策记录
This commit is contained in:
2026-06-19 02:18:36 +08:00
parent 75cd4f1abc
commit 429e65952d
12 changed files with 192 additions and 16 deletions
@@ -329,4 +329,29 @@ describe('nativeAppHostBridge', () => {
expect(listener).toHaveBeenCalledTimes(1);
expect(listener).toHaveBeenCalledWith({ canGoBack: true });
});
test('忽略未知宿主事件名', () => {
window.ReactNativeWebView = {
postMessage: vi.fn(),
};
const listener = vi.fn();
subscribeNativeAppHostBridgeEvent('navigation.canGoBack', listener);
window.dispatchEvent(
new MessageEvent('message', {
data: JSON.stringify({
bridge: HOST_BRIDGE_PROTOCOL,
version: HOST_BRIDGE_VERSION,
event: 'unknown.event',
payload: {
canGoBack: true,
},
}),
origin: window.location.origin,
source: window,
}),
);
expect(listener).not.toHaveBeenCalled();
});
});
@@ -4,9 +4,11 @@ import {
HOST_BRIDGE_VERSION,
type HostBridgeError,
type HostBridgeEvent,
type HostBridgeEventName,
type HostBridgeMethod,
type HostBridgeRequest,
type HostBridgeResponse,
isHostBridgeEventName,
} from '../../../packages/shared/src/contracts/hostBridge';
const DEFAULT_NATIVE_APP_BRIDGE_TIMEOUT_MS = 8000;
@@ -101,7 +103,7 @@ function isHostBridgeEvent(value: unknown): value is HostBridgeEvent {
return (
candidate.bridge === HOST_BRIDGE_PROTOCOL &&
candidate.version === HOST_BRIDGE_VERSION &&
typeof candidate.event === 'string'
isHostBridgeEventName(candidate.event)
);
}
@@ -230,7 +232,7 @@ export function canUseNativeAppHostBridge() {
}
export function subscribeNativeAppHostBridgeEvent<Payload = unknown>(
eventName: string,
eventName: HostBridgeEventName,
listener: (payload: Payload | undefined) => void,
) {
ensureNativeBridgeListener();