接入移动壳返回栈事件

移动壳声明 host.events 和 navigation.canGoBack 能力

Expo WebView 导航状态变化时向 H5 注入返回栈事件

H5 native_app transport 支持订阅 HostBridge 事件

补充事件订阅测试、移动壳能力测试和配置守卫

更新宿主壳方案和团队共享决策记录
This commit is contained in:
2026-06-17 22:42:44 +08:00
parent a87f3dcc82
commit 6f19e1c3ba
9 changed files with 125 additions and 6 deletions

View File

@@ -16,6 +16,12 @@ import { buildMobileShellUrl } from './src/mobileShellUrl';
const defaultWebUrl = 'http://127.0.0.1:3000/';
const hostVersion = '0.1.0';
function buildHostBridgeMessageScript(message: unknown) {
return `window.dispatchEvent(new MessageEvent('message', { data: ${JSON.stringify(
JSON.stringify(message),
)} })); true;`;
}
export default function App() {
const webViewRef = useRef<WebView>(null);
const [canGoBack, setCanGoBack] = useState(false);
@@ -91,9 +97,7 @@ export default function App() {
const handleMessage = (event: WebViewMessageEvent) => {
void handleMobileHostBridgeMessage(event.nativeEvent.data, (response) => {
webViewRef.current?.injectJavaScript(
`window.dispatchEvent(new MessageEvent('message', { data: ${JSON.stringify(
JSON.stringify(response),
)} })); true;`,
buildHostBridgeMessageScript(response),
);
});
};
@@ -118,7 +122,19 @@ export default function App() {
originWhitelist={[allowedWebOrigin]}
onMessage={handleMessage}
onShouldStartLoadWithRequest={handleShouldStartLoad}
onNavigationStateChange={(event) => setCanGoBack(event.canGoBack)}
onNavigationStateChange={(event) => {
setCanGoBack(event.canGoBack);
webViewRef.current?.injectJavaScript(
buildHostBridgeMessageScript({
bridge: 'GenarrativeHostBridge',
version: 1,
event: 'navigation.canGoBack',
payload: {
canGoBack: event.canGoBack,
},
}),
);
}}
setSupportMultipleWindows={false}
/>
</View>

View File

@@ -41,6 +41,8 @@ for (const snippet of [
"Linking.addEventListener('url'",
'buildMobileShellUrlFromDeepLink',
'configureMobileHostBridgeNavigation',
'navigation.canGoBack',
'buildHostBridgeMessageScript',
]) {
if (!appSource.includes(snippet)) {
throw new Error(`mobile shell App missing ${snippet}`);

View File

@@ -101,6 +101,11 @@ describe('handleMobileHostBridgeMessage', () => {
expect(
(okResponse.result as { capabilities: string[] }).capabilities,
).toContain('navigation.openNativePage');
expect(
(okResponse.result as { capabilities: string[] }).capabilities,
).toEqual(
expect.arrayContaining(['host.events', 'navigation.canGoBack']),
);
});
test('navigation.openNativePage 把同源路径切到移动壳 WebView', async () => {

View File

@@ -22,9 +22,11 @@ import { resolveMobileShellWebViewUrl } from './mobileShellNavigation';
export const MOBILE_HOST_CAPABILITIES: HostBridgeCapability[] = [
'host.getRuntime',
'host.events',
'share.open',
'share.setTarget',
'navigation.openNativePage',
'navigation.canGoBack',
'app.openExternalUrl',
'clipboard.writeText',
'haptics.impact',