From a865ac766b5d17974880857889d302fcc6e47910 Mon Sep 17 00:00:00 2001 From: lanterngamescn Date: Thu, 25 Jun 2026 23:25:49 +0800 Subject: [PATCH] =?UTF-8?q?M5:=20BridgeController=20=E6=BF=80=E6=B4=BB?= =?UTF-8?q?=E9=97=B8=E9=97=A8=20setActive=EF=BC=88=E5=8F=8C=20Web=20?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E4=BB=B6=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - BridgeController 加 active 状态 + setActive/isActive: - 非激活:onLoadIntercept 拦截 yy:// 但不分发(入站忽略)、dispatch 直接返回(出站抑制) - 保证双 Web 下"同时只有一个 Web 执行桥接口",且去激活端不会收到 native 推送 - 去激活顺序约定:先 callHandler(appservice,'2')(彼时仍激活),再 setActive(false) - 单测新增 inactive_gate_suppresses_outbound_and_inbound;scripts/test.sh 通过 Co-Authored-By: Claude Opus 4.8 (1M context) --- entry/src/test/Bridge.test.ets | 20 +++++++++++++++++++ .../src/main/ets/core/BridgeController.ets | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/entry/src/test/Bridge.test.ets b/entry/src/test/Bridge.test.ets index f30c08e..0b36d82 100644 --- a/entry/src/test/Bridge.test.ets +++ b/entry/src/test/Bridge.test.ets @@ -188,6 +188,26 @@ export default function bridgeTest() { expect(bridge.getRegistry().has('a')).assertFalse(); }); + it('inactive_gate_suppresses_outbound_and_inbound', 0, () => { + const fake = new FakeWebController(); + const bridge = new BridgeController(fake); + bridge.onPageEnd(); + let got = ''; + bridge.registerHandler('echo', (data, cb) => { got = data; cb('R'); }); + // 去激活:出站抑制 + bridge.setActive(false); + bridge.callHandler('appservice', '2'); + expect(fake.scripts.length).assertEqual(0); + // 去激活:入站忽略——yy:// 仍拦截(返回 true)但不 flush + const intercepted = bridge.onLoadIntercept('yy://__queue__/'); + expect(intercepted).assertTrue(); + expect(fake.scripts.length).assertEqual(0); + // 重新激活:恢复出站 + bridge.setActive(true); + bridge.callHandler('appservice', '1'); + expect(fake.scripts.some((s) => s.includes('appservice'))).assertTrue(); + }); + it('default_handler_unregistered_no_throw', 0, () => { const fake = new FakeWebController(); const bridge = new BridgeController(fake); diff --git a/feature_bridge/src/main/ets/core/BridgeController.ets b/feature_bridge/src/main/ets/core/BridgeController.ets index ca64c13..60c9ad6 100644 --- a/feature_bridge/src/main/ets/core/BridgeController.ets +++ b/feature_bridge/src/main/ets/core/BridgeController.ets @@ -26,6 +26,8 @@ export class BridgeController { private startupMessages: Message[] | null = []; private uniqueId: number = 0; private bridgeJs: string = ''; + /** 激活闸门(M5 双 Web):非激活时入站不分发、出站不下发,保证同时只有一个 Web 在执行桥接口。 */ + private active: boolean = true; constructor(web: IWebController, registry?: HandlerRegistry) { this.web = web; @@ -41,6 +43,16 @@ export class BridgeController { this.bridgeJs = js; } + /** 设激活态(M5 双 Web 激活协议)。非激活:入站忽略、出站抑制。 + * 注意:去激活前应先下发 appservice('2')(彼时仍激活),再 setActive(false)。 */ + setActive(active: boolean): void { + this.active = active; + } + + isActive(): boolean { + return this.active; + } + /** 释放:清空回执表/注册表/启动队列,断开与已注册能力闭包的引用,防泄漏。 * 容器 aboutToDisappear 调用(注意:IWebController 由容器另行 dispose)。 */ dispose(): void { @@ -57,6 +69,10 @@ export class BridgeController { } catch (e) { url = rawUrl; } + // 非激活:拦截 yy:// 但不处理(非激活 Web 的桥接口不执行;H5 已由 appservice('2') 进入后台态) + if (!this.active) { + return url.startsWith(YY_SCHEMA); + } if (url.startsWith(YY_RETURN)) { this.handleReturnData(url); return true; @@ -172,6 +188,10 @@ export class BridgeController { } private dispatch(m: Message): void { + // 非激活:抑制出站(native→H5 不下发到非激活 Web)。激活时机由 WebSlotManager 控制顺序。 + if (!this.active) { + return; + } // lzyzsd 二次转义(复刻 \ 与 ");再补转义单引号——lzyzsd 原版遗漏,而出站脚本用 // 单引号包裹 _handleMessageFromNative('...'),data 含 ' 会提前闭合字符串。补转义后 // H5 JSON.parse 得到的仍是原始 data,对 H5 完全透明(边界行为不变)。