查看原文
其他

技术分享|同层渲染之高德地图

邹同学 明源云天际PaaS平台 2022-09-10

源宝导读:在移动Hybrid应用中,开发者如果想要实现复杂的UI效果,并且在性能和用户体验上也有所要求时,往往没有较好的实现方案。本文将分享一个新技术同层渲染技术来解决这些问题,旨在提升用户体验,解决WebView兼容问题。

一、背景

客户反馈高德地图有性能问题和兼容问题,在某些手机上会出现滑动不流畅或崩溃的情况,原因是他们使用的是web版本的高德地图,web版本的地图因为渲染于WebView上,所以天然不如原生地图所具备的性能和兼容性。

为了解决用户问题,我们想到的方案是在之前web地图的部分用原生地图来代替,非地图的部分还是用h5来显示,这样既能提高性能,又能满足业务团队的自定义业务需求。这个方案初步看来就是cordova调用原生功能的一个普通插件,实现起来没有什么难度。但是...

我们观察了下web实现的效果,发现地图上面还有多个功能入口,比如"项目总数"、"资产总数"、"资产面积"、"项目详情"等,这些元素都是悬浮在地图上的。这种h5和原生的混合渲染方式在技术上并不容易实现,而且对于手势分发(web或原生对手势的响应)也得进行额外的处理。

带着这些问题,我们进行了一系列的尝试和实验,最终将问题解决并开发了"同层渲染——高德地图插件"。


二、调研

基于用户的需求和问题,我们思考和尝试了多个方案:

1. web页面和原生地图分别属于两个独立的页面,在使用地图的时候,通过cordova接口打开一个新的页面,在新的页面内,原生地图按照传入的参数,提供原生开发的业务功能。

经过了解,客户团队的APP是需要在一级页面内使用地图,所以这种方案不符合客户的需求。

2. web页面和原生地图位于同一个页面内,其中多个h5元素分别采用独立的WebView进行渲染。

显而易见的,这个方案将分别对需要渲染的H5元素生成多个WebView,不仅对于系统的性能造成浪费,而且多个WebView的通信、位置等等都没法很好的处理,所以该方案也不行。

3. 基于Android提供的WebView的PPAPI插件能力,开发一个地图的WebPlugin插件。

理论上来说,这个方案是最好的方案,一举解决了用户的问题,并且还提供了完美的自定义扩展。但是据我们查阅网上的资料,发现该方案已经在新版本的Chromium中被删除了,也就是说谷歌不再提供支持该方案。而且这个方案还存在一个问题,由于需要编译浏览器内核并集成在APP中,将会明显的增加APP的体积。基于开发周期和其他内容的综合考虑,所以也没有采用这个方案。

调研结论:没有合适的方案能够解决用户的问题。我们当然不能选择解决用户,所以...


三、新方案

我们重新考虑了客户的业务场景,决定把页面分为两层,下层是原生地图层,上层为WebView层,如下图所示:

我们期望的效果是:

1. 点击web元素时,点击事件由WebView处理

2. 点击原生地图区域时,点击事件由地图处理

3. web与原生地图间的信息交互由cordova插件接口来实现

实现思路:

1. 原生地图位于下层,WebView置于原生地图上,并将WebView的背景设置为透明,将可以透过WebView看到下面的地图内容。

2. 增加一个手势分发层,通过计算来判断手势发生在web元素还是地图上。如果发生在web元素上,则直接由WebView处理,如果发生在地图上,则直接由地图响应。

3. web调用地图的一些功能则通过cordova插件接口来实现。比如:绘制覆盖物、获取定位、获取中心点、设置缩放、移动地图等。


四、实现

4.1 手势处理

为解决手势问题,我们需要将web元素的具体位置传入到手势分发层。所以需要在屏幕上建立一个坐标系,如下图所示:

1. 设屏幕左上角为原点,web端调用js方法分别获得web元素(绿色方框标记)的坐标,如(0, 0, 300, 50)、(20, 300, 260, 50)、(0, 380, 300, 50),格式为(left, top, width, height)。

2. 通过调用cordova接口,将元素的坐标传入手势分发层。如果Web元素的区域会发生变化,则在每次变化后,需要将新的坐标信息重新传入。

3. 当用户触摸屏幕时,在手势分发层获取用户触摸的位置,然后与传入的坐标进行比较判断。如果是发生在web元素上,则由WebView处理事件(如动画、路由等),否则交由地图处理(如移动地图、缩放地图等)。

4.2 关键代码

1. 手势分发层关键代码

按照之前设计的方案,在WebView层(背景透明)下,把地图层插入进去,这样WebView层就叠加在地图层上。用数组记录Web端传入的坐标信息,当用户触摸屏幕时,通过dispatchTouchEvent获取手指信息,然后遍历坐标数组,判断手指手指位置是否与坐标矩形区域相交,如果相交,则分发给WebView层,否则分发给地图。

public boolean dispatchTouchEvent(MotionEvent event) { boolean isTouchedWebView = false; if(event.getAction() == MotionEvent.ACTION_DOWN) { // 判断是否触摸在Web元素上 isTouchedWebView = regionManager.isWebElementTouchEvent(event); } if(isTouchedWebView) { // 分发给WebView return super.dispatchTouchEvent(event); } else { // 分发给地图 return regionManager.dispatchMapViewTouchEvent(event); }}

2. WebView层

该层主要包括两类接口:同层渲染通用接口;调用地图功能接口。

3. 地图层

该层在高德地图的基础上做了封装,提供一些具体的业务功能接口,包括地图的基本操作、添加覆盖物等。

4.3 效果对比

Web地图效果(图片较大,耐心等待)

原生地图效果(图片较大,耐心等待)

4.4 问题及处理方案

问题一:新方案需要在WebView的下层将地图View添加进去,以及在处理手势冲突时需要重写WebView的dispatchTouchEvent方法。

处理方案:我们引入AspectJ框架来实现AOP方案,在不改变其他插件代码的同时,调用我们自定义的功能代码。充分与其他插件进行解耦。

问题二:Web在同时调用地图功能时,被调用的操作不会全部执行。

处理方案:事实上这是高德地图的一个缺陷,为了规避这个问题,我们采用了队列的方案,将用户调用地图功能的操作缓存到队列中,按次序的进行执行。

问题三:添加地图覆盖物性能问题:切换覆盖物空白期较长、切换时间过长。

处理方案:针对空白期较长问题,我们加入了覆盖物动画效果,感官减少了突兀感。针对切换时间过长问题,我们将用户需要绘制的数据按照距离屏幕中心点进行排序,距离屏幕中心最近的点先开始绘制,效果提升显著。


五、 小结

本文主要描述了为解决用户问题而调研并实现方案的过程,期间走了挺多的弯路,但这个方案的落地还是为未来我们提升用户体验、提高插件扩展能力提供了一些参考。

目前,基于这个同层渲染方案我们另外还实现了一个图库插件,该插件只提供基础的大图浏览功能,但是具体的业务功能,业务方将可以最大程度的进行自定义。

未来,我们将继续基于该方案实现更多的特性插件,于此同时,我们将继续研究Chromium内核,在内核层实现真正的同层渲染方案。

------ END ------
作者简介
邹同学: 研发工程师,目前负责移动平台相关工作。

也许您还想看:
技术分享|Java SDK 动态类型
技术分享|文件预览方案在应用市场的落地

更多明源云·天际开放平台场景案例与开发小知识,可以关注明源云天际开发者社区公众号:
建模零代码之(树)列表的多级列头
【集成】API 参数映射之 JavaScript引擎介绍
【建模】用户自定义搜索条件,检索效率快人一步


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存