review: M0/M1 成果审查后的质量加固
三路独立审查:桥引擎(对照 lzyzsd 逐字)与契约 SSOT(对照原 Android 44 handler) 两个命门维度【零问题】;以下为架构/质量改进项的修复: - [安全红线] BridgeGameContainer setWebDebuggingAccess 加 AppEnv.isDebug() 守卫 (common 新增 AppEnv,用 bundleManager.appInfo.debug 运行时判断,release 自动关闭, 消除 CLAUDE.md 附录B 红线违反) - [生命周期] BridgeController 加 dispose() 清回执表/注册表/启动队列;HandlerRegistry 加 clear();容器 aboutToDisappear 先 dispose 桥再 dispose adapter 并置空,防残留命中/泄漏 - [事件总线] EventBus.on/once 返回取消函数支持 per-subscriber 精确退订;off→offAll 并 标注谨慎(避免 M3 多容器订阅 appservice 时误注销他人回调) - [单测] 加强 escape 断言覆盖内层 " 加倍(命门);新增 dispose 用例;16 用例全通过, 桥核心覆盖率 89.0% - [记录] Index.pageMap param as 运行期不校验,M4 外部 scheme 唤起时需补校验(已注释) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
74b302e131
commit
bdb920f61e
@@ -1,5 +1,6 @@
|
||||
import { webview } from '@kit.ArkWeb';
|
||||
import { BridgeController, WebviewControllerAdapter, BridgeJsLoader } from 'feature_bridge';
|
||||
import { AppEnv } from 'common';
|
||||
import { BridgeGameParams } from '../routes/AppRoutes';
|
||||
|
||||
/**
|
||||
@@ -17,15 +18,24 @@ export struct BridgeGameContainer {
|
||||
private bridge: BridgeController | undefined = undefined;
|
||||
|
||||
aboutToAppear(): void {
|
||||
// 开发期开启远程调试;M5 加固时用 BuildProfile.DEBUG 守卫、release 必关(附录 B)
|
||||
webview.WebviewController.setWebDebuggingAccess(true);
|
||||
// 远程调试仅 debug 包开启,release 自动关闭(CLAUDE.md 附录 B 红线)
|
||||
if (AppEnv.isDebug()) {
|
||||
webview.WebviewController.setWebDebuggingAccess(true);
|
||||
}
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
// 释放:先清桥(回执表/注册表/启动队列),再断 UI 线程通道,最后置空防残留命中
|
||||
const b = this.bridge;
|
||||
if (b !== undefined) {
|
||||
b.dispose();
|
||||
}
|
||||
const a = this.adapter;
|
||||
if (a !== undefined) {
|
||||
a.dispose();
|
||||
}
|
||||
this.bridge = undefined;
|
||||
this.adapter = undefined;
|
||||
}
|
||||
|
||||
private setupBridge(): void {
|
||||
|
||||
@@ -17,6 +17,8 @@ struct Index {
|
||||
this.pathStack.pushPathByName(RouteName.SPLASH, '', false);
|
||||
}
|
||||
|
||||
// 注:param as T 为编译期断言、运行期不校验。本期由 Splash 固定传对象,安全;
|
||||
// M4 接入外部 scheme 唤起(gamepaywelcome 等深链)时,需在此对 param 做运行期类型校验后再下发。
|
||||
@Builder
|
||||
pageMap(name: string, param: object) {
|
||||
if (name === RouteName.SPLASH) {
|
||||
|
||||
@@ -34,12 +34,17 @@ export default function bridgeTest() {
|
||||
});
|
||||
|
||||
it('escape_quotes_backslash', 0, () => {
|
||||
// JSON {"data":"a\"b"} → 结构引号转义、内部 \" 加倍
|
||||
// data='a"b' → toJson 得 {"data":"a\"b"}(内部引号被 JSON 转义为 \")
|
||||
const mm = new Message();
|
||||
mm.data = 'a"b';
|
||||
const escaped = MessageCodec.escape(MessageCodec.toJson(mm));
|
||||
// 结构引号被转义为 \"(前面非反斜杠)
|
||||
const json = MessageCodec.toJson(mm);
|
||||
// toJson 内部:a 与 b 之间是 反斜杠+引号
|
||||
expect(json.includes('a\\"b')).assertTrue();
|
||||
const escaped = MessageCodec.escape(json);
|
||||
// 第二步:结构引号(前面非反斜杠)被转义为 \"
|
||||
expect(escaped.includes('\\"data\\"')).assertTrue();
|
||||
// 第一步(命门):内部已转义的 \" 的反斜杠被加倍 → a 与 b 之间出现 \\\"(反斜杠×2+引号)
|
||||
expect(escaped.includes('a\\\\\\"b')).assertTrue();
|
||||
});
|
||||
|
||||
it('toArray_parses_queue', 0, () => {
|
||||
@@ -173,6 +178,16 @@ export default function bridgeTest() {
|
||||
expect(resp).assertEqual('1700');
|
||||
});
|
||||
|
||||
it('dispose_clears_registry_and_callbacks', 0, () => {
|
||||
const fake = new FakeWebController();
|
||||
const bridge = new BridgeController(fake);
|
||||
bridge.registerHandler('a', (_d, cb) => cb('A'));
|
||||
expect(bridge.getRegistry().has('a')).assertTrue();
|
||||
bridge.dispose();
|
||||
// dispose 清空注册表(默认兜底保留)
|
||||
expect(bridge.getRegistry().has('a')).assertFalse();
|
||||
});
|
||||
|
||||
it('default_handler_unregistered_no_throw', 0, () => {
|
||||
const fake = new FakeWebController();
|
||||
const bridge = new BridgeController(fake);
|
||||
|
||||
Reference in New Issue
Block a user