收紧移动壳能力声明与迟到响应边界
移动壳卸载后丢弃迟到 HostBridge 响应 移动壳 ShellApp 测试覆盖卸载后异步响应不注入 移动壳配置检查拒绝只返回 unsupported 的声明能力 共享决策记录补充移动壳消息注入和能力声明约定
This commit is contained in:
@@ -390,6 +390,26 @@ function extractMobileBridgeHandledMethods(source) {
|
||||
return [...match[1].matchAll(/case '([^']+)':/g)].map((entry) => entry[1]);
|
||||
}
|
||||
|
||||
function extractMobileBridgeUnsupportedMethods(source) {
|
||||
const match = source.match(
|
||||
/async function dispatchMobileHostBridgeRequest[\s\S]*?switch \(request\.method\) \{([\s\S]*?)\n \}/,
|
||||
);
|
||||
if (!match) {
|
||||
throw new Error('unable to read mobile shell HostBridge unsupported methods');
|
||||
}
|
||||
|
||||
const unsupportedMethods = new Set();
|
||||
const casePattern =
|
||||
/case '([^']+)':([\s\S]*?)(?=\n case '|\n default:|\n \})/g;
|
||||
for (const entry of match[1].matchAll(casePattern)) {
|
||||
if (entry[2].includes('unsupported(request.method)')) {
|
||||
unsupportedMethods.add(entry[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return [...unsupportedMethods];
|
||||
}
|
||||
|
||||
function extractFunctionBody(source, functionName) {
|
||||
const start = source.indexOf(`function ${functionName}`);
|
||||
if (start === -1) {
|
||||
@@ -821,6 +841,7 @@ if (sharedPublicWebOriginUrl.protocol !== 'https:') {
|
||||
const sharedPublicWebHost = sharedPublicWebOriginUrl.hostname;
|
||||
const sharedPublicWebAssociatedDomain = `applinks:${sharedPublicWebHost}`;
|
||||
const handledMobileMethods = extractMobileBridgeHandledMethods(dispatchSource);
|
||||
const unsupportedMobileMethods = extractMobileBridgeUnsupportedMethods(dispatchSource);
|
||||
const mobileCapabilities = sharedMobileBaseCapabilities;
|
||||
const iosMobileCapabilities = sharedMobileIosCapabilities;
|
||||
const mobileCapabilitySet = new Set(mobileCapabilities);
|
||||
@@ -1054,6 +1075,17 @@ if (missingMobileMethodHandlers.length > 0) {
|
||||
);
|
||||
}
|
||||
|
||||
const unsupportedMobileCapabilities = iosMobileCapabilities.filter(
|
||||
(capability) =>
|
||||
sharedMethods.includes(capability) &&
|
||||
unsupportedMobileMethods.includes(capability),
|
||||
);
|
||||
if (unsupportedMobileCapabilities.length > 0) {
|
||||
throw new Error(
|
||||
`mobile shell declares request capabilities backed only by unsupported responses: ${unsupportedMobileCapabilities.join(', ')}`,
|
||||
);
|
||||
}
|
||||
|
||||
const undeclaredMobileMethodHandlers = handledMobileMethods.filter(
|
||||
(method) =>
|
||||
!iosMobileCapabilitySet.has(method) && !sdkBackedCapabilities.includes(method),
|
||||
@@ -1375,6 +1407,7 @@ for (const snippet of [
|
||||
'h5CanGoBackRef',
|
||||
'syncNavigationCanGoBack',
|
||||
'resetNavigationCanGoBack',
|
||||
'isShellMountedRef',
|
||||
'injectHostBridgeMessage',
|
||||
'injectHostBridgeEvent',
|
||||
'injectLifecycleEvent',
|
||||
@@ -1382,6 +1415,7 @@ for (const snippet of [
|
||||
'logMobileHostEventFailure',
|
||||
'logMobileHostBridgeMessageFailure',
|
||||
'try {',
|
||||
'if (!isShellMountedRef.current)',
|
||||
'logMobileHostEventFailure(event, error)',
|
||||
'injectHostBridgeMessage(response, logMobileHostBridgeMessageFailure)',
|
||||
"console.warn('mobile HostBridge message injection failed', error)",
|
||||
@@ -2451,6 +2485,8 @@ for (const snippet of [
|
||||
"test('logs HostBridge response injection failures without crashing the shell'",
|
||||
"new Error('response injection failed')",
|
||||
'mobile HostBridge message injection failed',
|
||||
"test('drops delayed HostBridge responses after shell unmount'",
|
||||
"id: 'network-request-1'",
|
||||
"type: 'genarrative.mobile.historyState'",
|
||||
'mobile host event failed for network.statusChanged',
|
||||
'external WebView navigation native failures stay outside the WebView',
|
||||
|
||||
Reference in New Issue
Block a user