因公司甲方要求,需要在APP中直接集成百度地图公交路径规划功能,方便用户出行;当然用户也可以直接用百度、或高德去查询,但作为交通出行类的工具类型APP,如果能直接提供辅助型的核心功能,再配合运营工具,不仅能提高用户粘性,还能对用户查询使用习惯进行分析。
功能流程
用户搜索目标位置,从当前位置进行公交线路查询,提供详细的换乘信息和地图线路绘制。UI上面的交互比较复杂,不仅地图上要绘制线路,前景UI详情面板需要展示站点路径详情(起终点、公交线路信息、换乘站、时间、步行距离、总共站点数等),而且需要支持多种规划方案左右滑动切换,上下滑动能显示和隐藏详情面板,整套功能和在高德中查询交互方式几乎一致。
情况分析
地图定位、路径规划、POI检索功能在百度地图SDK里面可以轻松实现,一开始觉得用原生的方式实现应该没有问题,无奈UI排版和交互上的功能比较多,而且工期比较紧张,需要在两周内正常交付,且需要Android和iOS两端都实现;前端组当时的资源非常紧张,每个人几乎都在并行开发多个项目冲刺deadline,如果要抽出两个完整人力全身心开发这个功能不太现实,试想人家高德、百度专业做这一块在资源充裕的情况下也不是两周把功能开发完,我们这种一肩扛的码农就更不必说了;所以,本人最终说(shui)服了领导使用RN的技术栈(RN已有多个迭代沉淀趋于稳定,所以暂不考虑Flutter),以节省人力成本为前提,两端复用UI交互方式(-0.8个人力),百度SDK的功能两端必须实现, 以1.2个人力按时交付完成;
实现方式
从功能上看,js主要实现业务逻辑和UI,原生对百度地图SDK做二次封装,提供桥接代码供js端调用,而路径规划、POI检索功能有两种方案:
- js直接调用百度Web服务API获取搜索结果
- js调用原生百度SDK获取搜索结果
第一种方案相对来说比较简单,不需要原生支持就能实现,但是调起Web服务API有配额限制,点击查看;而调用原生SDK没有配额限制,在日均pv超10w的情况下采用第二种方案更加合理
整体架构如下:
- js business层实现所有业务代码和UI
- js map封装js端的地图视图模块和路径规划、POI检索等桥接工具
- 原生Android/iOS对百度地图SDK进行封装,提供地图视图、路径规划、POI检索原生桥接代码
百度地图BaiduMapView
原生端封装百度SDK mapView,作为js端的组件引入,可控制展示区域;
提供缩放等级、添加覆盖物、地图中心、路径规划结果展示、开启用户定位点、侦听用户定位坐标等能力;
地图工具BaiduMapAppModule
js请求原生端查询地图信息;提供检查定位权限、跳转开启定位权限页面、获取路径规划结果、获取POI关键字检索结果等能力;
地址查询(POI检索)
用户选择起点位置或终点位置后进入;
用户输入后通过BaiduMapAppModule获取POI关键字检索结果,展示详细地址列表;
用户选择地址后记录在搜索历史中,供下次搜索前快速选取;
公交路径规划
起点或终点信息输入后开始公交路径规划;
通过BaiduMapAppModule获取路径规划结果,由js展示样式信息;
若起终点位置太近、跨城市搜索将无法获取公交路径规划结果抛出异常;
js banner组件
纯js封装的组件,提供数据传入、item样式、当前选中页、侦听滑动页变化等能力;
实际场景:在获取到公交方案后,将方案信息存入;定制初始选中页,切换页面后触发页面变化展示线路内容详情;
js 嵌套滚动组件
纯js封装的组件,包含两层滚动组件,外层滚动控制容器位置,内层滚动展示详情信息;外层容器拖动会更新位置,上下轻扫会到达外层容器位置边界;当内层滚动到边界的时候,会触发外层容器位置滚动;
实际场景:当获取到公交内容信息详情后,用户控制拖动容器、或向下轻扫可查看背景地图路线图;用户可上下滚动查看公交换乘详情内容,当内容滚动到顶部的时候继续滚动外部容器位置变化更新;
采用PanResponder手势组件实现,对外层滚动位置和内层详情滚动位置分别进行侦听控制,触发边界以后控制两层手势对应的交互开关。使用方法
技术难点
- 百度地图视图ViewManager封装
- 因iOS和Android从百度SDK返回的结果字段名和结构不尽相同,如果直接拿原始值返回给js使用会出现不统一的问题,需要对结果进行二次转换,统一字段名和数据结构
- js PanResponder实现嵌套滚动,在手势结束以后需要对滑动方向继续做惯性运动,模拟ScrollView的滚动,参考文档