Files
Genarrative/apps/mobile-shell/src/mobileShellDeepLink.ts
T
kdletters 3b3e83aa7a 收紧移动壳启动地址归一
Expo 移动壳只接受 http 和 https 基准 H5 地址

非法启动地址回退默认 H5 并继续附加宿主上下文

Deep link 继续限制为同源 H5 路径

补充启动地址检查测试和架构文档
2026-06-18 08:19:25 +08:00

70 lines
1.7 KiB
TypeScript

import {
buildMobileShellUrl,
resolveMobileShellBaseWebUrl,
type MobileShellUrlOptions,
} from './mobileShellUrl';
const supportedHosts = new Set(['open', 'app']);
function extractPathFromNativeUrl(url: URL) {
if (supportedHosts.has(url.hostname)) {
return `${url.pathname}${url.search}${url.hash}`;
}
return `${url.hostname ? `/${url.hostname}` : ''}${url.pathname}${url.search}${url.hash}`;
}
function resolveTargetPath(rawUrl: string, webOrigin: string) {
try {
const url = new URL(rawUrl);
if (url.protocol === 'genarrative:') {
return extractPathFromNativeUrl(url);
}
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
return null;
}
if (url.origin !== webOrigin) {
return null;
}
return `${url.pathname}${url.search}${url.hash}`;
} catch {
if (!rawUrl.startsWith('/') && !rawUrl.startsWith('#')) {
return null;
}
try {
const relativeUrl = new URL(rawUrl, webOrigin);
if (relativeUrl.origin !== webOrigin) {
return null;
}
return `${relativeUrl.pathname}${relativeUrl.search}${relativeUrl.hash}`;
} catch {
return null;
}
}
}
export function buildMobileShellUrlFromDeepLink(
rawUrl: string | null | undefined,
baseWebUrl: string,
options: MobileShellUrlOptions,
) {
const normalizedBaseWebUrl = resolveMobileShellBaseWebUrl(baseWebUrl);
const defaultUrl = buildMobileShellUrl(normalizedBaseWebUrl, options);
if (!rawUrl) {
return defaultUrl;
}
const webOrigin = new URL(normalizedBaseWebUrl).origin;
const targetPath = resolveTargetPath(rawUrl, webOrigin);
if (!targetPath) {
return defaultUrl;
}
return buildMobileShellUrl(new URL(targetPath, webOrigin).toString(), options);
}