接入移动壳受控路由导航
移动 HostBridge 声明 navigation.openNativePage 并限制为同源 H5 route Expo WebView 将受控导航请求切换为新的 WebView URL 补充移动壳 HostBridge 与导航解析测试和配置守卫 更新宿主壳方案、统一协议和团队共享决策记录
This commit is contained in:
@@ -13,20 +13,35 @@ import {
|
||||
type HostBridgeMethod,
|
||||
type HostBridgeRequest,
|
||||
type HostBridgeResponse,
|
||||
type NavigateNativePagePayload,
|
||||
type OpenExternalUrlPayload,
|
||||
type ShareOpenPayload,
|
||||
} from '../../../packages/shared/src/contracts/hostBridge';
|
||||
import { resolveMobileShellWebViewUrl } from './mobileShellNavigation';
|
||||
|
||||
export const MOBILE_HOST_CAPABILITIES: HostBridgeCapability[] = [
|
||||
'host.getRuntime',
|
||||
'share.open',
|
||||
'share.setTarget',
|
||||
'navigation.openNativePage',
|
||||
'app.openExternalUrl',
|
||||
'clipboard.writeText',
|
||||
'haptics.impact',
|
||||
];
|
||||
|
||||
export type MobileHostBridgeNavigation = {
|
||||
allowedOrigin: string;
|
||||
openWebViewUrl: (url: string) => void;
|
||||
};
|
||||
|
||||
let currentShareTarget: unknown = null;
|
||||
let navigation: MobileHostBridgeNavigation | null = null;
|
||||
|
||||
export function configureMobileHostBridgeNavigation(
|
||||
nextNavigation: MobileHostBridgeNavigation | null,
|
||||
) {
|
||||
navigation = nextNavigation;
|
||||
}
|
||||
|
||||
function unsupported(method: HostBridgeMethod): HostBridgeError {
|
||||
return {
|
||||
@@ -141,6 +156,28 @@ async function openShare(payload: unknown) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function openNativePage(payload: unknown) {
|
||||
if (!navigation) {
|
||||
throw unsupported('navigation.openNativePage');
|
||||
}
|
||||
|
||||
const url = (payload as NavigateNativePagePayload | undefined)?.url;
|
||||
if (typeof url !== 'string') {
|
||||
throw invalidRequest('url is required');
|
||||
}
|
||||
|
||||
const webViewUrl = resolveMobileShellWebViewUrl(
|
||||
url,
|
||||
navigation.allowedOrigin,
|
||||
);
|
||||
if (!webViewUrl) {
|
||||
throw invalidRequest('url must be an allowed same-origin web path');
|
||||
}
|
||||
|
||||
navigation.openWebViewUrl(webViewUrl);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function handleRequest(request: HostBridgeRequest) {
|
||||
switch (request.method) {
|
||||
case 'host.getRuntime':
|
||||
@@ -165,9 +202,10 @@ async function handleRequest(request: HostBridgeRequest) {
|
||||
? (request.payload as { target?: unknown }).target
|
||||
: null;
|
||||
return ok(request, true);
|
||||
case 'navigation.openNativePage':
|
||||
return ok(request, openNativePage(request.payload));
|
||||
case 'auth.requestLogin':
|
||||
case 'payment.request':
|
||||
case 'navigation.openNativePage':
|
||||
return failure(request, unsupported(request.method));
|
||||
default:
|
||||
return failure(request, unsupported(request.method));
|
||||
|
||||
Reference in New Issue
Block a user