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:
zizi 2026-06-11 02:45:31 +00:00
parent 7ab0cfacc3
commit b8d1a0da73

View File

@ -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=undefinedpost() 静默丢弃
* 全部 hostgame 消息storage/ad/pay 回包与 init 全断gamehost 不受影响故两波未现形
* 取元素一律走 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-originincludeNull=true + origin
const allowed = buildOriginAllowlist(pendingAllowOrigins, /* includeNull */ true);
const win = iframe.contentWindow;
if (!win) {
// hostgame storage/ad/pay
// eslint-disable-next-line no-console
console.warn('[GamePlayer] attachBridgeiframe.contentWindow 不可用host→game 方向将不可达');
}
bridge = new HostBridge({
targetWindow: iframe.contentWindow,
targetWindow: win,
allowedOrigins: allowed,
onMessage: handleEnvelope,
onReject: handleReject,