修改chromium内核,实现小程序的Map组件同层渲染(Android端)

2,710 阅读3分钟

一、渲染问题

(一)地图接口对接

同层渲染的关键点,前一篇 修改chromium内核,实现小程序的camera组件同层渲染(Android端)已经说明了实现方向和思路,embed标签对应的区域关联了一个SurfaceTexture,我们只需要把地图渲染到这个SurfaceTexture就行。目前市面上的常见地图SDK,腾讯的开放了接口,支持地图渲染到SurfaceTexture。下面代码是简单的创建地图例子。

通过MapRenderLayer创建地图
SurfaceTexture surface =new SurfaceTexture(TEXTURE_ID);
TencentMapOptions mapOptions = new TencentMapOptions();
mapOptions.setExtSurface(surface);
mapOptions.setExtSurfaceDimension(900, 900);
MapRenderLayer mapView = new MapRenderLayer(context, mapOptions);
parentView.addView(mapView);

(二)关键类SurfaceTexture和Surface

参考一下Android官网文档SurfaceSurfaceTexture

Surface是一个接口,供生产方与消耗方交换缓冲区。

SurfaceTexture 是 Surface 和 OpenGL ES (GLES) 纹理的组合。SurfaceTexture 实例用于提供输出到 GLES 纹理的接口。SurfaceTexture 包含一个以应用为使用方的 BufferQueue 实例。当生产方将新的缓冲区排入队列时,onFrameAvailable() 回调会通知应用。然后,应用调用 updateTexImage(),这会释放先前占用的缓冲区,从队列中获取新缓冲区并执行EGL调用,从而使 GLES 可将此缓冲区作为外部纹理使用。

根据官网的文档说明和流程图,我们把这段文字分成两半再来捋一下:

  1. SurfaceTexture 是 Surface 和 OpenGL ES (GLES) 纹理的组合。SurfaceTexture 实例用于提供输出到 GLES 纹理的接口。个人觉得下面可以这几行代码解释:

int[] glTextures = new int[1];
// 生成一个纹理id存在glTextures数组内
GLES20.glGenTextures(1, glTextures, 0);
SurfaceTexture surfaceTexture = new SurfaceTexture(glTextures[0]);
Surface surface = new Surface(surfaceTexture);

  1. SurfaceTexture 包含一个以应用为使用方的 BufferQueue 实例。当生产方将新的缓冲区排入队列时,onFrameAvailable() 回调会通知应用。然后,应用调用 updateTexImage(),这会释放先前占用的缓冲区,从队列中获取新缓冲区并执行 EGL 调用,从而使 GLES 可将此缓冲区作为外部纹理使用。

Chromium Compositor 使用SurfaceTexture合成地图画面数据,是消费侧。地图SDK向Surface内写入数据,是生产侧。当地图SDK写入数据到Surface内时,chromium使用SurfaceTexture注册的onFrameAvailable() 回调执行,它去获取最新的数据参与整个web页面的合成,最终显示在屏幕上。

(三)基于同层组件渲染数据的生产者/消费者示意图

chromium同层渲染简单上屏流程.jpg

二、手势问题

(一)手势冲突的问题

众所周知,在Android端,网页是可以支持滑动及双指缩放的,而地图也刚好是需要响应处理这些手势,那么就遇到了一个麻烦的问题:

  1. 如果跳过web页面直接把事件派发给原生组件处理,则破坏了网页的滑动及缩放功能。
  2. 如果直接把事件派发给了web页面且Map组件没有机会响应手势,则破坏了地图的功能。

(二)手势处理的优先级及预期效果

为了让Map组件和web页面达到无缝融合的效果,所以Map组件的手势处理的优先级及规则也应该像一个普通的web元素一样,不能破坏整个web规范。

应该有以下场景及预期效果, 假设给到一个Map组件在网页上且其它网页区域不处理事件。

  1. Map组件需要处理手势
    (1) 手势触发在其它网页区域时,网页应缩放或者滑动
    (2) 手势触发在Map组件区域时,地图内容应缩放或者滑动
  2. Map组件忽略手势时 手势触发在任何区域时,网页应缩放或者滑动

(三)同层组件手势处理流程图:

经过一番研究,有两个关键点会影响手势事件的派发

  1. 是否注册了touch事件的监听
  2. 第一步注册时,passive是否设为了true

chromium同层渲染插件Touch Event流程图.jpg

三、做一个demo看看效果

1.gif

四、下期预告(如果有):

把Android原生的View作为一个同层组件渲染到网页的embed标签上。