diff --git a/entry/src/main/ets/web/WebSlot.ets b/entry/src/main/ets/web/WebSlot.ets index dcfb9bf..6c3f05d 100644 --- a/entry/src/main/ets/web/WebSlot.ets +++ b/entry/src/main/ets/web/WebSlot.ets @@ -100,29 +100,33 @@ export class WebSlot { onPageEnd(): void { this.bridgeCtrl?.onPageEnd(); - this.injectCompositingKeepAlive(); + this.injectTouchMouseShim(); } /** - * 🔴 合成保活(修复 H5 内 canvas 动画"定格不上屏")。 - * 现象:ArkWeb 默认 ASYNC 渲染下,H5 用 requestAnimationFrame 逐帧重绘 (JS 在跑、 - * 像素在变),但 ArkWeb 判定"组件内容未变"不再产出新合成帧,于是 canvas 更新不上屏—— - * 表现为按钮按下缩放等 canvas 动画定格(连上 DevTools 会强制持续合成,故调试时正常)。 - * 修法(H5 零改动,原生注入):插入一个不可见、独立合成层(will-change:transform)的 1px 元素, - * 每帧微动其 transform,强制 ArkWeb 持续产出合成帧,把 canvas 一并刷上屏(等效 DevTools 效果)。 - * rAF 在页面不可见/后台时自动暂停,故仅前台活跃期有开销。每次 onPageEnd 注入,window.__arkKA 幂等。 + * 🔴 触摸→鼠标时序修正 shim(修复 H5 引擎"按钮按下缩放"等鼠标驱动效果在触摸下失效)。 + * 现象:引擎(gameabc)的按下缩放绑在 mousedown(缩小)/mouseup(还原)。Android WebView 触摸合成的 + * 鼠标事件按真实按住时长跨开,而 ArkWeb 触摸把合成的 mousedown/mouseup **挤在抬手后的 ~12ms 内**, + * 致缩放一闪而过看不见;click 正常故功能无碍。(chrome://inspect 用真鼠标,时序正常,故调试时正常。) + * 修法(H5 零改动,原生注入):preventDefault(touchstart) 抑制 ArkWeb 那套**错时**的原生合成鼠标事件, + * 改由 pointer 事件按真实时序补发 mousedown/mousemove/mouseup/click(仅 touch 指针)——单次、时序正确, + * 不会重复触发。引擎仅监听鼠标事件(触摸时序本正确却失效即证),故无双触发。每次 onPageEnd 注入,幂等。 */ - private injectCompositingKeepAlive(): void { + private injectTouchMouseShim(): void { const script: string = - "(function(){if(window.__arkKA)return;window.__arkKA=1;" + - "var d=document.createElement('div');" + - "d.style.cssText='position:fixed;left:0;top:0;width:1px;height:1px;opacity:0.02;pointer-events:none;z-index:2147483647;will-change:transform';" + - "function add(){var r=document.body||document.documentElement;if(!r){setTimeout(add,50);return;}r.appendChild(d);" + - "var n=0;(function t(){n^=1;d.style.transform='translateZ(0) translateX('+n+'px)';requestAnimationFrame(t);})();}add();})();"; + "(function(){if(window.__msShim)return;window.__msShim=1;" + + "function fire(type,ev){var t=ev.target||document.elementFromPoint(ev.clientX,ev.clientY)||document.body;" + + "t.dispatchEvent(new MouseEvent(type,{bubbles:true,cancelable:true,view:window,detail:1,clientX:ev.clientX,clientY:ev.clientY,screenX:ev.screenX,screenY:ev.screenY,button:0}));}" + + "var down=false;" + + "document.addEventListener('touchstart',function(e){if(e.cancelable)e.preventDefault();},{passive:false,capture:true});" + + "document.addEventListener('pointerdown',function(ev){if(ev.pointerType!=='touch')return;down=true;fire('mousedown',ev);},true);" + + "document.addEventListener('pointermove',function(ev){if(ev.pointerType!=='touch'||!down)return;fire('mousemove',ev);},true);" + + "document.addEventListener('pointerup',function(ev){if(ev.pointerType!=='touch'||!down)return;down=false;fire('mousemove',ev);fire('mouseup',ev);fire('click',ev);},true);" + + "document.addEventListener('pointercancel',function(ev){if(ev.pointerType!=='touch'||!down)return;down=false;fire('mouseup',ev);},true);})();"; try { this.controller.runJavaScript(script); } catch (e) { - WebSlot.log.w(`[${this.role}] keep-alive inject failed: ${(e as BusinessError).message}`); + WebSlot.log.w(`[${this.role}] touch-mouse shim inject failed: ${(e as BusinessError).message}`); } }