WebView 同层渲染

H5 具有开发成本较低、跨平台、快速迭代等优点,但 WebView 在性能上相比 Native 会有一定的劣势,如在资源加载比较多的场景下会导致内存占用过高、滚动卡顿、部分格式图片格式不支持等问题。针对这些问题,客户端可对图片和视频等资源进行原生渲染,即实现 WebView 同层渲染。

iOS

实现原理

WKWebView 在进行 HTML 解析时,会根据页面 DOM 元素在 WKWebView 控件下生成对应的 iOS 原生控件。但通常情况下,生成的原生控件与 HTML 节点无对应关系,但在某些特殊情况下,一些特殊 DOM 元素会在 WebView 的对应位置生成位置、大小完全一致的原生控件:

  • CSS 属性满足:overflow: scroll; -webkit-overflow-scrolling: touch;
  • 子元素高度或宽度超出该 DOM 的高度或宽度形成弹性滚动

iOS 13 之前,上面两个条件都需要满足;iOS 13 只需满足上面任一条件即可。

详细步骤

  1. 前端预先在需要插入原生控件的位置插入一个具有 overflow 属性的 div 标签,通知客户端该滚动条的位置、大小;
  2. 客户端根据前端传入的位置和大小,在 WKWebView 下遍历找到这个 div 标签对应的 UIScrollView (大小位置均一致),保存其对象指针,并分配一个 id 返回给前端;
  3. 客户端根据前端传入的位置和大小,在 WKWebView 下遍历找到这个 div 标签对应的 UIScrollView (大小位置均一致),保存其对象指针,并分配一个 id 返回给前端;

手势问题

由于 WKWebView 会接管用户的所有操作事件,因此按照上述方案插入后,原生控件是无法响应用户事件的。需要对事件做特殊处理:通过重载 WKWebView 的 hitTest 方法,在该方法的处理逻辑中优先处理网页上的事件,如果网页未处理,再传递给原生控件。

Android

实现原理

Chromium 内核支持 WebPlugin 机制,WebPlugin 是浏览器内核的一个插件机制,主要用来解析和描述 embed 标签。Android 端的同层渲染就是基于 embed 标签结合 Chromium 内核扩展来实现的。

详细步骤

  1. WebView 侧创建一个 embed DOM 节点并指定组件类型;
  2. Chromium 内核会创建一个 WebPlugin 实例,并生成一个 RenderLayer
  3. Android 客户端初始化一个对应的原生组件;
  4. Android 客户端将原生组件的画面绘制到步骤 2 创建的 RenderLayer 所绑定的 SurfaceTexture 上;
  5. 通知 Chromium 内核渲染该 RenderLayer
  6. Chromium 渲染该 embed 节点并上屏。

参考资料

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享