81c353e586
移动壳 URL 构建默认拒绝本机 H5 入口 Deep Link 与原生页导航显式传递开发态入口选项 补充移动壳 URL 与 Deep Link 边界测试 同步原生壳门禁和项目决策日志
103 lines
2.6 KiB
TypeScript
103 lines
2.6 KiB
TypeScript
import {
|
|
HOST_BRIDGE_NATIVE_APP_QUERY,
|
|
HOST_BRIDGE_NATIVE_APP_QUERY_KEY,
|
|
HOST_BRIDGE_PUBLIC_WEB_ORIGIN,
|
|
HOST_BRIDGE_PUBLIC_WEB_URL,
|
|
HOST_BRIDGE_VERSION,
|
|
type HostBridgeCapability,
|
|
type NativeHostPlatform,
|
|
} from '../../../../packages/shared/src/contracts/hostBridge';
|
|
|
|
export type MobileShellUrlOptions = {
|
|
platform: Extract<NativeHostPlatform, 'ios' | 'android'>;
|
|
hostVersion: string;
|
|
capabilities: readonly HostBridgeCapability[];
|
|
};
|
|
|
|
export type MobileShellBaseWebUrlOptions = {
|
|
allowLocalDevelopment?: boolean;
|
|
};
|
|
|
|
export const DEFAULT_MOBILE_SHELL_WEB_URL = HOST_BRIDGE_PUBLIC_WEB_URL;
|
|
export const ALLOWED_PRODUCTION_WEB_ORIGIN = HOST_BRIDGE_PUBLIC_WEB_ORIGIN;
|
|
const LOCAL_DEVELOPMENT_WEB_HOSTS = new Set([
|
|
'127.0.0.1',
|
|
'localhost',
|
|
'[::1]',
|
|
]);
|
|
|
|
function isAllowedMobileShellBaseUrl(
|
|
url: URL,
|
|
options: MobileShellBaseWebUrlOptions = {},
|
|
) {
|
|
if (url.origin === ALLOWED_PRODUCTION_WEB_ORIGIN) {
|
|
return true;
|
|
}
|
|
|
|
return Boolean(options.allowLocalDevelopment) &&
|
|
url.protocol === 'http:' &&
|
|
LOCAL_DEVELOPMENT_WEB_HOSTS.has(url.hostname);
|
|
}
|
|
|
|
export function resolveMobileShellBaseWebUrl(
|
|
rawUrl: unknown,
|
|
options: MobileShellBaseWebUrlOptions = {},
|
|
) {
|
|
if (typeof rawUrl !== 'string') {
|
|
return DEFAULT_MOBILE_SHELL_WEB_URL;
|
|
}
|
|
|
|
const value = rawUrl.trim();
|
|
if (!value) {
|
|
return DEFAULT_MOBILE_SHELL_WEB_URL;
|
|
}
|
|
|
|
try {
|
|
const url = new URL(value);
|
|
if (!isAllowedMobileShellBaseUrl(url, options)) {
|
|
return DEFAULT_MOBILE_SHELL_WEB_URL;
|
|
}
|
|
|
|
return url.toString();
|
|
} catch {
|
|
return DEFAULT_MOBILE_SHELL_WEB_URL;
|
|
}
|
|
}
|
|
|
|
export function buildMobileShellUrl(
|
|
rawUrl: string,
|
|
options: MobileShellUrlOptions,
|
|
baseWebUrlOptions: MobileShellBaseWebUrlOptions = {},
|
|
) {
|
|
const url = new URL(resolveMobileShellBaseWebUrl(rawUrl, baseWebUrlOptions));
|
|
url.searchParams.set(
|
|
HOST_BRIDGE_NATIVE_APP_QUERY_KEY.clientRuntime,
|
|
HOST_BRIDGE_NATIVE_APP_QUERY.clientRuntime,
|
|
);
|
|
url.searchParams.set(
|
|
HOST_BRIDGE_NATIVE_APP_QUERY_KEY.clientType,
|
|
HOST_BRIDGE_NATIVE_APP_QUERY.clientType,
|
|
);
|
|
url.searchParams.set(
|
|
HOST_BRIDGE_NATIVE_APP_QUERY_KEY.hostShell,
|
|
HOST_BRIDGE_NATIVE_APP_QUERY.hostShellExpoMobile,
|
|
);
|
|
url.searchParams.set(
|
|
HOST_BRIDGE_NATIVE_APP_QUERY_KEY.hostPlatform,
|
|
options.platform,
|
|
);
|
|
url.searchParams.set(
|
|
HOST_BRIDGE_NATIVE_APP_QUERY_KEY.hostVersion,
|
|
options.hostVersion,
|
|
);
|
|
url.searchParams.set(
|
|
HOST_BRIDGE_NATIVE_APP_QUERY_KEY.bridgeVersion,
|
|
HOST_BRIDGE_VERSION.toString(),
|
|
);
|
|
url.searchParams.set(
|
|
HOST_BRIDGE_NATIVE_APP_QUERY_KEY.hostCapabilities,
|
|
options.capabilities.join(','),
|
|
);
|
|
return url.toString();
|
|
}
|