保持移动壳主动导航宿主上下文
HostBridge 主动导航同源页面时重新附加 native_app 宿主参数 补充移动壳导航测试覆盖平台版本和能力清单 同步 Expo/Tauri 宿主壳方案和团队决策记录
This commit is contained in:
@@ -21,6 +21,7 @@ import {
|
||||
type HostBridgeRequest,
|
||||
type HostBridgeResponse,
|
||||
} from '../../../../packages/shared/src/contracts/hostBridge';
|
||||
import type { MobileShellUrlOptions } from '../shell/url';
|
||||
import {
|
||||
configureMobileHostBridgeNavigation,
|
||||
handleMobileHostBridgeMessage,
|
||||
@@ -46,6 +47,12 @@ const DENIED_NOTIFICATION_PERMISSION = {
|
||||
|
||||
let requestSequence = 0;
|
||||
|
||||
const TEST_MOBILE_URL_OPTIONS: MobileShellUrlOptions = {
|
||||
platform: 'ios',
|
||||
hostVersion: '0.1.0',
|
||||
capabilities: ['host.getRuntime', 'share.open'],
|
||||
};
|
||||
|
||||
vi.mock('expo-clipboard', () => ({
|
||||
getStringAsync: vi.fn(),
|
||||
setStringAsync: vi.fn(),
|
||||
@@ -388,6 +395,7 @@ describe('handleMobileHostBridgeMessage', () => {
|
||||
const openWebViewUrl = vi.fn();
|
||||
configureMobileHostBridgeNavigation({
|
||||
allowedOrigin: 'https://app.genarrative.world',
|
||||
urlOptions: TEST_MOBILE_URL_OPTIONS,
|
||||
openWebViewUrl,
|
||||
reloadWebView: vi.fn(),
|
||||
});
|
||||
@@ -399,14 +407,24 @@ describe('handleMobileHostBridgeMessage', () => {
|
||||
);
|
||||
|
||||
expectOk(response);
|
||||
expect(openWebViewUrl).toHaveBeenCalledWith(
|
||||
'https://app.genarrative.world/works/detail?work=PZ-1',
|
||||
const openedUrl = new URL(openWebViewUrl.mock.calls[0]?.[0] as string);
|
||||
expect(openedUrl.origin).toBe('https://app.genarrative.world');
|
||||
expect(openedUrl.pathname).toBe('/works/detail');
|
||||
expect(openedUrl.searchParams.get('work')).toBe('PZ-1');
|
||||
expect(openedUrl.searchParams.get('clientRuntime')).toBe('native_app');
|
||||
expect(openedUrl.searchParams.get('hostShell')).toBe('expo_mobile');
|
||||
expect(openedUrl.searchParams.get('hostPlatform')).toBe('ios');
|
||||
expect(openedUrl.searchParams.get('hostVersion')).toBe('0.1.0');
|
||||
expect(openedUrl.searchParams.get('bridgeVersion')).toBe('1');
|
||||
expect(openedUrl.searchParams.get('hostCapabilities')).toBe(
|
||||
'host.getRuntime,share.open',
|
||||
);
|
||||
});
|
||||
|
||||
test('navigation.openNativePage 拒绝外域目标', async () => {
|
||||
configureMobileHostBridgeNavigation({
|
||||
allowedOrigin: 'https://app.genarrative.world',
|
||||
urlOptions: TEST_MOBILE_URL_OPTIONS,
|
||||
openWebViewUrl: vi.fn(),
|
||||
reloadWebView: vi.fn(),
|
||||
});
|
||||
@@ -475,6 +493,7 @@ describe('handleMobileHostBridgeMessage', () => {
|
||||
const reloadWebView = vi.fn();
|
||||
configureMobileHostBridgeNavigation({
|
||||
allowedOrigin: 'https://app.genarrative.world',
|
||||
urlOptions: TEST_MOBILE_URL_OPTIONS,
|
||||
openWebViewUrl: vi.fn(),
|
||||
reloadWebView,
|
||||
});
|
||||
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
unsupported,
|
||||
} from './protocol';
|
||||
import { openShare } from './share';
|
||||
import { buildMobileShellUrl } from '../shell/url';
|
||||
|
||||
const LOCAL_NOTIFICATION_CHANNEL_ID = 'genarrative-local';
|
||||
|
||||
@@ -222,7 +223,9 @@ function openNativePage(payload: unknown) {
|
||||
throw invalidRequest('url must be an allowed same-origin web path');
|
||||
}
|
||||
|
||||
navigation.openWebViewUrl(webViewUrl);
|
||||
navigation.openWebViewUrl(
|
||||
buildMobileShellUrl(webViewUrl, navigation.urlOptions),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@ import {
|
||||
isHostBridgeMethod,
|
||||
normalizeHostBridgeRequestId,
|
||||
} from '../../../../packages/shared/src/contracts/hostBridge';
|
||||
import type { MobileShellUrlOptions } from '../shell/url';
|
||||
|
||||
export const HOST_BRIDGE_RESPONSE_CACHE_MAX = 128;
|
||||
|
||||
export type MobileHostBridgeNavigation = {
|
||||
allowedOrigin: string;
|
||||
urlOptions: MobileShellUrlOptions;
|
||||
openWebViewUrl: (url: string) => void;
|
||||
reloadWebView: () => void;
|
||||
};
|
||||
|
||||
@@ -89,6 +89,7 @@ export default function ShellApp() {
|
||||
useEffect(() => {
|
||||
configureMobileHostBridgeNavigation({
|
||||
allowedOrigin: allowedWebOrigin,
|
||||
urlOptions,
|
||||
openWebViewUrl(url) {
|
||||
setWebUrl(url);
|
||||
},
|
||||
@@ -96,7 +97,7 @@ export default function ShellApp() {
|
||||
});
|
||||
|
||||
return () => configureMobileHostBridgeNavigation(null);
|
||||
}, [allowedWebOrigin, reloadCurrentWebView]);
|
||||
}, [allowedWebOrigin, reloadCurrentWebView, urlOptions]);
|
||||
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
|
||||
Reference in New Issue
Block a user