fix(runtime-host): host→game 回包全断根因修复——v-for 模板 ref 数组解包
根因(探针四锚点+判别实验实证):ref=iframeRef 位于 v-for 内,Vue 3 填充为数组; attachBridge 按元素直取 (数组).contentWindow=undefined → HostBridge.targetWindow= undefined → post() 静默丢弃全部 host→game(storage/ad/pay 回包+init 同断)。 game→host 监听全局 window 不受影响,故游戏可玩/遥测可达,两波未现形。 修法:currentIframe() 解包 + contentWindow 不可用时显式 console.warn(可观测)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
7ab0cfacc3
commit
b8d1a0da73
@ -55,10 +55,24 @@ type LoadPhase = 'idle' | 'loading' | 'ready' | 'error';
|
||||
const phase = ref<LoadPhase>('idle');
|
||||
const errorMsg = ref('');
|
||||
|
||||
/** iframe 元素引用与 srcdoc 内容 */
|
||||
const iframeRef = ref<HTMLIFrameElement | null>(null);
|
||||
/**
|
||||
* iframe 元素引用与 srcdoc 内容。
|
||||
* ⚠ 模板里 ref="iframeRef" 位于 v-for="slot in containers" 内部——Vue 3 对 v-for 内的
|
||||
* 模板 ref 填充的是【数组】而非元素(即使只渲染 1 个 iframe)。曾因按元素直接取
|
||||
* .contentWindow 得 undefined,致 HostBridge.targetWindow=undefined、post() 静默丢弃
|
||||
* 全部 host→game 消息(storage/ad/pay 回包与 init 全断;game→host 不受影响故两波未现形)。
|
||||
* 取元素一律走 currentIframe() 解包,勿直接读 iframeRef.value。
|
||||
*/
|
||||
const iframeRef = ref<HTMLIFrameElement | HTMLIFrameElement[] | null>(null);
|
||||
const srcdoc = ref('');
|
||||
|
||||
/** 解包 v-for 数组形态的模板 ref,返回当前唯一 iframe 元素(无则 null)。 */
|
||||
function currentIframe(): HTMLIFrameElement | null {
|
||||
const v = iframeRef.value;
|
||||
if (Array.isArray(v)) return v[0] ?? null;
|
||||
return v;
|
||||
}
|
||||
|
||||
/** 宿主桥实例(onMounted 后创建,卸载时 dispose) */
|
||||
let bridge: HostBridge | null = null;
|
||||
|
||||
@ -200,16 +214,23 @@ let pendingAllowOrigins: string[] | undefined;
|
||||
|
||||
/** 在 iframe 渲染后建立桥(含双校验) */
|
||||
function attachBridge(): void {
|
||||
const iframe = iframeRef.value;
|
||||
const iframe = currentIframe(); // v-for 模板 ref 是数组,必须解包(见 iframeRef 声明注释)
|
||||
if (!iframe) return;
|
||||
// 先销毁旧桥
|
||||
bridge?.dispose();
|
||||
|
||||
// origin 白名单:srcdoc 注入文档 origin='null',需 includeNull=true 才能收到 iframe 消息。
|
||||
// origin 白名单:srcdoc 沙箱按 sandbox 形态 origin 可能为 'null'(无 allow-same-origin)
|
||||
// 或与宿主同源(现行 allow-same-origin),两种均入白名单(includeNull=true + 自身 origin)。
|
||||
const allowed = buildOriginAllowlist(pendingAllowOrigins, /* includeNull */ true);
|
||||
|
||||
const win = iframe.contentWindow;
|
||||
if (!win) {
|
||||
// host→game 出口不可用是致命静默故障(storage/ad/pay 回包全断),必须可观测
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('[GamePlayer] attachBridge:iframe.contentWindow 不可用,host→game 方向将不可达');
|
||||
}
|
||||
bridge = new HostBridge({
|
||||
targetWindow: iframe.contentWindow,
|
||||
targetWindow: win,
|
||||
allowedOrigins: allowed,
|
||||
onMessage: handleEnvelope,
|
||||
onReject: handleReject,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user