一、渲染问题
(一)地图接口对接
同层渲染的关键点,前一篇 修改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官网文档Surface和SurfaceTexture
Surface是一个接口,供生产方与消耗方交换缓冲区。
SurfaceTexture是 Surface 和 OpenGL ES (GLES) 纹理的组合。SurfaceTexture实例用于提供输出到 GLES 纹理的接口。SurfaceTexture包含一个以应用为使用方的BufferQueue实例。当生产方将新的缓冲区排入队列时,onFrameAvailable()回调会通知应用。然后,应用调用updateTexImage(),这会释放先前占用的缓冲区,从队列中获取新缓冲区并执行EGL调用,从而使 GLES 可将此缓冲区作为外部纹理使用。
根据官网的文档说明和流程图,我们把这段文字分成两半再来捋一下:
- 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);
- SurfaceTexture 包含一个以应用为使用方的 BufferQueue 实例。当生产方将新的缓冲区排入队列时,onFrameAvailable() 回调会通知应用。然后,应用调用 updateTexImage(),这会释放先前占用的缓冲区,从队列中获取新缓冲区并执行 EGL 调用,从而使 GLES 可将此缓冲区作为外部纹理使用。
Chromium Compositor 使用SurfaceTexture合成地图画面数据,是消费侧。地图SDK向Surface内写入数据,是生产侧。当地图SDK写入数据到Surface内时,chromium使用SurfaceTexture注册的onFrameAvailable() 回调执行,它去获取最新的数据参与整个web页面的合成,最终显示在屏幕上。
(三)基于同层组件渲染数据的生产者/消费者示意图
二、手势问题
(一)手势冲突的问题
众所周知,在Android端,网页是可以支持滑动及双指缩放的,而地图也刚好是需要响应处理这些手势,那么就遇到了一个麻烦的问题:
- 如果跳过web页面直接把事件派发给原生组件处理,则破坏了网页的滑动及缩放功能。
- 如果直接把事件派发给了web页面且Map组件没有机会响应手势,则破坏了地图的功能。
(二)手势处理的优先级及预期效果
为了让Map组件和web页面达到无缝融合的效果,所以Map组件的手势处理的优先级及规则也应该像一个普通的web元素一样,不能破坏整个web规范。
应该有以下场景及预期效果, 假设给到一个Map组件在网页上且其它网页区域不处理事件。
- Map组件需要处理手势
(1) 手势触发在其它网页区域时,网页应缩放或者滑动
(2) 手势触发在Map组件区域时,地图内容应缩放或者滑动- Map组件忽略手势时 手势触发在任何区域时,网页应缩放或者滑动
(三)同层组件手势处理流程图:
经过一番研究,有两个关键点会影响手势事件的派发
- 是否注册了touch事件的监听
- 第一步注册时,passive是否设为了true
三、做一个demo看看效果
四、下期预告(如果有):
把Android原生的View作为一个同层组件渲染到网页的embed标签上。