M1: 容器接桥 + V1 阻塞性验证通过(T-M1-05/06/07)
- BridgeGameContainer 挂 Web + 接桥:onControllerAttached 建桥/注册 handler、
onLoadIntercept 接桥、onPageEnd 注桥 JS + 补发启动队列、aboutToDisappear 释放
- test_echo.html 最小回显 H5(getTime 往返 + nativeEcho 特殊字符转义往返)
- 修复:dispatch 出站补转义单引号——lzyzsd 原版遗漏,_handleMessageFromNative('...')
单引号包裹下 data 含 ' 会破坏字符串;补转义对 H5 透明(JSON.parse 仍得原始 data)
- ⚠ V1 真机通过:yy:// 被 onLoadIntercept 捕获、_fetchQueue 经 yy://return 回传、
双向回执、含 "\/'中文 特殊字符转义往返一致。技术路线成立,无需回退
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
206db9730a
commit
3e2b1282ba
@@ -164,8 +164,12 @@ export class BridgeController {
|
||||
}
|
||||
|
||||
private dispatch(m: Message): void {
|
||||
const json = MessageCodec.escape(MessageCodec.toJson(m));
|
||||
this.web.runJavaScript(`WebViewJavascriptBridge._handleMessageFromNative('${json}');`);
|
||||
// lzyzsd 二次转义(复刻 \ 与 ");再补转义单引号——lzyzsd 原版遗漏,而出站脚本用
|
||||
// 单引号包裹 _handleMessageFromNative('...'),data 含 ' 会提前闭合字符串。补转义后
|
||||
// H5 JSON.parse 得到的仍是原始 data,对 H5 完全透明(边界行为不变)。
|
||||
const escaped = MessageCodec.escape(MessageCodec.toJson(m));
|
||||
const safe = escaped.replace(/'/g, "\\'");
|
||||
this.web.runJavaScript(`WebViewJavascriptBridge._handleMessageFromNative('${safe}');`);
|
||||
}
|
||||
|
||||
// —— BridgeUtil 等价:从回执 URL 解析 functionName / data ——
|
||||
|
||||
@@ -24,44 +24,42 @@ export interface IWebController {
|
||||
export class WebviewControllerAdapter implements IWebController {
|
||||
private static seq: number = 0;
|
||||
private readonly controller: webview.WebviewController;
|
||||
private readonly uiEventId: string;
|
||||
private readonly jsEventId: string;
|
||||
private readonly urlEventId: string;
|
||||
|
||||
constructor(controller: webview.WebviewController) {
|
||||
this.controller = controller;
|
||||
WebviewControllerAdapter.seq += 1;
|
||||
this.uiEventId = `web.ui.runjs.${WebviewControllerAdapter.seq}`;
|
||||
// 构造发生在 UI 线程(容器内)→ 订阅回调即在 UI 线程执行
|
||||
emitter.on(this.uiEventId, (ev: emitter.EventData) => {
|
||||
const d = ev.data;
|
||||
if (d === undefined) {
|
||||
return;
|
||||
this.jsEventId = `web.ui.js.${WebviewControllerAdapter.seq}`;
|
||||
this.urlEventId = `web.ui.url.${WebviewControllerAdapter.seq}`;
|
||||
// 构造发生在 UI 线程(容器内)→ 订阅回调即在 UI 线程执行(泛型 string payload,无 any)
|
||||
emitter.on<string>(this.jsEventId, (ev: emitter.GenericEventData<string>) => {
|
||||
const s = ev.data;
|
||||
if (s !== undefined) {
|
||||
this.controller.runJavaScript(s).then(() => { }).catch((_e: Object) => { });
|
||||
}
|
||||
const script = d['script'];
|
||||
if (typeof script === 'string') {
|
||||
this.controller.runJavaScript(script).then(() => { }).catch((_e: Object) => { });
|
||||
return;
|
||||
}
|
||||
const url = d['loadUrl'];
|
||||
if (typeof url === 'string') {
|
||||
this.controller.loadUrl(url);
|
||||
});
|
||||
emitter.on<string>(this.urlEventId, (ev: emitter.GenericEventData<string>) => {
|
||||
const u = ev.data;
|
||||
if (u !== undefined) {
|
||||
this.controller.loadUrl(u);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
runJavaScript(script: string): void {
|
||||
const payload: Record<string, Object> = { 'script': script };
|
||||
const ev: emitter.EventData = { data: payload };
|
||||
emitter.emit(this.uiEventId, ev);
|
||||
const ev: emitter.GenericEventData<string> = { data: script };
|
||||
emitter.emit<string>(this.jsEventId, ev);
|
||||
}
|
||||
|
||||
loadUrl(url: string): void {
|
||||
const payload: Record<string, Object> = { 'loadUrl': url };
|
||||
const ev: emitter.EventData = { data: payload };
|
||||
emitter.emit(this.uiEventId, ev);
|
||||
const ev: emitter.GenericEventData<string> = { data: url };
|
||||
emitter.emit<string>(this.urlEventId, ev);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
emitter.off(this.uiEventId);
|
||||
emitter.off(this.jsEventId);
|
||||
emitter.off(this.urlEventId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user