高德客户端及引擎技术架构演进与思考

2019 年 11 月 19 日

高德客户端及引擎技术架构演进与思考

2019 杭州云栖大会上,高德地图技术团队向与会者分享了包括视觉与机器智能、路线规划、场景化/精细化定位、时空数据应用、亿级流量架构演进等多个出行技术领域的热门话题。现场火爆,听众反响强烈。我们把其中的优秀演讲内容整理成文并陆续发布在「高德技术」公众号上,本文为其中一篇。


2019 杭州云栖大会高德技术专场讲师系列:



阿里巴巴高级无线开发专家宋照春在高德技术专场做了题为《高德客户端及引擎技术架构演进与思考》的演讲,主要分享了高德地图客户端技术架构沿着「上漂下沉」、「模块化、Bundle 化」的思路演进所做的一系列架构升级中的经验和思考。


以下为宋照春演讲内容的简版实录


主要分享三个方面的内容:


  • 融合

  • 架构治理

  • 动态化


一、三管齐下 深度融合


高德最初有两个端,车机版的高德导航,手机版的高德地图,两个团队,一个是 2B,一个是 2C,分别是汽车业务和手机业务。当时在引擎/技术上,分为离线引擎和在线引擎,但两个团队之间交流比较少,各自有自己的研发、产品和测试,而作为一款端上的 APP,两块业务都需要有地图渲染、路线规划、导航以及定位等通用能力。从公司层面看,存在较大的重复建设,整体研发效率较低。



于是我们做了一件事:利用技术手段,打通端上引擎,打造一套能同时支撑多端的 APP 能力。具体到执行层面,先从 A 团队拉一部分人到 B 团队一起建设,建设完之后再从 B 团队拉到 A 团队。在同时支撑好主线业务发展的情况下,通过一年左右时间,完成了引擎上的融合,做到同时支撑手机、车机以及开放平台。



这样就从引擎的维度,实现了渲染、定位、规划和引导的统一。具体来说,我们的各大引擎有好多套代码,好几个开发团队,每个团队有各自的开发方式和开发环境(Linux,Windows,Mac OS)。各种开发环境,工程配置文件大量重复,修改非常繁琐。


为此,我们通过两种方法:


  1. 建立了一套构建系统Abtor,通过一个配置系统实现统一构建,能够同时支持多个子引擎,在构建集成效率上得到了很大的提升;

  2. 对基础库进行了整体重构,形成了一套涵盖了文件I/O、KV存储、多线程框架&异步框架、归档、基础容器等一系列标准能力的基础库,同时也做了引擎核心架构的统一。



二、架构治理


通过引擎的融合同时支持多端,在研发效率上实现比较大的收益。而通过技术的抓手来实现团队的融合,对公司发展而言,这其实是更大的收益,团队融合的意义在于人才拉通和复用,组织效率得到了较大提升。


随着高德业务的快速发展,业务上持续扩品类,需求量激增,高德地图从最初的驾车导航,到后来的步行、骑行、摩托车导航等等,App 所承载的业务发展非常快,而原有的架构治理模式的问题也逐渐暴露出来。


首先就是 App 的代码规模变得特别大。当时一个仓库达到了 10G 以上,由此导致的一个典型的问题就是编译慢,编译出一次安装包需要一个小时。伴随代码规模的另一个问题是团队规模快速增长。代码增长和大团队并行开发,最终导致合版慢,每次迭代,客户端合版需要 2 天。


代码膨胀导致的架构腐化问题特别突出,所以测试质量以及线上的质量有段时间也比较差。此外,从产品提出需求到上线,平均需要 45 天,版本迭代周期很长


为解决以上架构问题,我们采取了三个手段:升级 Native 基础组件搭建 Native 容器和页面框架Bundle 化分拆(微应用)


下面重点介绍下页面框架和微应用。


页面框架主要借鉴和融合了 Android 和 iOS 的生命期管理机制。从高德地图 App 架构看,下层模块是一套标准地图,所有上层业务都要基于地图模块开发。为确保上层业务低耦合、一致性,我们设计了一个页面框架。



如上图,左边的 Activity 是 Android 的系统页面控制器,右边的 UIViewController 是 iOS 的系统页面控制器,通过虚线连接比较,我们发现两端的页面状态设计基本相同。


所以,我们在设计自己的页面框架时沿用了这些系统页面状态,同时从命名上也保持一致,这样可以让 Android 和 iOS 原生开发的同学更容易理解和上手。


我们吸取了双端各自的优点。比如,Android 端页面有四种启动模式,但是 iOS 端并没有这些,我们就把 Android 的四种启动模式运用到了 iOS 端;iOS 端有 Present 特性,但是 Android 端没有,那么也把这种特性融合到 Android 端的页面框架中;最后,还有一些小设计,比如 Android 的 onResult 设计,也可以借鉴融合到 iOS 端。


此外,我们还做了微应用,所谓微应用,首先是模块化,就是把大模块仓库大模块拆成一个个小的 Bundle,除了实现模块化,还主要实现以下几个目标:


  • 粒度:以业务为单位,以业务线为分组

  • 编译:二进制级别的产物,可独立编译、出包时链接

  • 依赖:松耦合,以“服务”为导向,不关心模块归属


而 Native 容器层面,要实现四个核心目标:路由管理、服务管理、UI 生命期管理、微应用管理。


通过一年时间的 Bundle 化改造,高德地图单端 App 完成了 300 多个页面的建设,拆分了 100 多个 Bundle。


从收益来看,总编译时间从原来的 60 分钟降低到了 8 分钟,合版周期从原来的 3 天降到 1 天,需求上线周期降到了 1 个月以内,线上质量和测试质量都得到了极大的提升,崩溃率从万分之八降低到十万分之八。


三、动态化


随着高德地图业务发展沿着扩品类、在垂直品类做精做细,景区、酒店、银行商铺、充电桩等个性化定制需求凸显,对前端展现提出了更高的要求,对“快速应变”要求也更高了。


实际上,在 2015 年,高德就开始做动态化。最早的时候业内就有 React Native,团队做了技术调研,发现不能完全满足业务上的需要,尤其是性能方面。最后我们决定自研一套动态化技术。


具体来说,就是通过一个核心 C++引擎,把两端业务(Android、iOS)用一套 JavaScript 代码解决,实现双端归一,Android 实现业务动态化发布。


架构层面,最下面是高德 App 核心的地图引擎,我们在上面搭建了一套动态化应用引擎,通过 C++来实现。应用引擎的作用是为了承上启下,上面承载动态化业务,下层完成地图引擎的直接打通。众所周知,GUI 的核心是 DOM 树,所以应用引擎不但要实现和 JavaScript 引擎的整合,还要负责 DOM 树的核心逻辑计算。


其次,动态化的技术和前端 Web 技术一致:样式、布局。应用引擎负责完成样式的布局计算、DOM 树 Diff、事件生成。而 GUI 的绘制,通过 Diff 事件,交由原生的 Android 以及 iOS 去完成。这样,所有的 GUI 都是原生的组件。


在之上,我们搭建了一套前端框架,前端框架采用当前前端响应式框架做,前端框架之上又搭建了一套前端的 UI 卡片库和 UI 组件库,让上层业务能够更高效的开发。


而对于一些通过动态化的技术无法实现,或者性能上存在卡点的功能,我们就通过 Native 扩展能力来支撑,这样,完整的动态化的业务能够直接运行在 Android 以及 iOS 上。



JS 去执行代码之后,前端框架会产生虚拟的 DOM 树,最后提交到 C++引擎,形成 C++的 DOM 树。C++引擎去完成布局、样式计算,Diff 计算,将每个节点的属性和坐标交给 Android 以及 iOS,由 Native 来完成最终 UI 的渲染。


总体来说,动态化的特点:首先是它与主流前端框架融合,充分融合了大前端的生态;第二,性能、扩展性较好。因为采用 C++实现整个核心逻辑,静态和动态的语言绑定技术,能够保证地图引擎的能力能够直接透出到上层,或者从上层能够直接 call 底层的 C++能力;第三,多端归一和动态化,充分利用 Native 优势,接近原生 Native 体验。


动态化技术改造完成之后,双端不一致的问题降低了 90%,开发、测试成本降低 30%,发版周期从 T+30 到 T+0。


最后,总结下高德客户端及引擎技术架构演进的几个重要阶段:第一个阶段,通过在线 &离线引擎的融合拉通,让高德最核心的导航能力提到提升;第二阶段,在客户端发展成为“巨型”APP,代码量发展到超大规模的时候,通过架构治理,满足业务快速增长的诉求,解决大规模业务体量下的架构合理性问题,消除架构瓶颈;第三个阶段通过动态化的技术,实现多端归一,以及动态发版能力,为业务发展提供更大的助力。


作者介绍


宋照春,阿里巴巴高级无线开发专家。


本文转载自公众号高德技术(ID:amap_tech)。


原文链接


https://mp.weixin.qq.com/s?__biz=Mzg4MzIwMDM5Ng==&mid=2247484387&idx=2&sn=fa5861004462f0c4486d9facb6cda690&chksm=cf4a5b00f83dd216af5268da64a4ded17714985000be65e13c67acf6f3613d20fc882d3e4125&scene=27#wechat_redirect


2019 年 11 月 19 日 08:001426

评论

发布
暂无评论
发现更多内容

从技术思维角度聊一聊『程序员』摆地摊的正确姿势

码大叔

随笔杂谈 技术人生 经验分享

存储让“想象”势不可挡

焱融科技

ChaosBlade:从零开始的混沌工程(一)

郭旭东

云原生 混沌工程

分布式系统技术:存储之数据库

奈学教育

分布式

实时更新:计算机编程语言排行榜—TIOBE世界编程语言排行榜(2020年6月份最新版)

ATGU:阿宝哥

9种 分布式ID生成方案,我替你整理好了

程序员内点事

Java MySQL 分布式

Dubbo Cluster集群那点你不知道的事。

why技术

源码 面试 dubbo 集群容错

Elasticsearch-Base

lee

elasticsearch search 搜索

读《平凡的世界》

YoungZY

读书

持续集成实践系列 」Jenkins 构建 CI 自动化流水线常见技巧 (二)

狂师

持续集成 jenkins jenkins-plugin CI/CD

原创 | TDD工具集:JUnit、AssertJ和Mockito (十八)编写测试-测试执行顺序\嵌套的测试

编程道与术

Java 编程 TDD 单元测试 JUnit

C#和TS的范型实例化

猫定谔的靴

C# typescript 泛型

从SDL到DevSecOps:始终贯穿开发生命周期的安全

Fooying

DevOps SDL DevSecOps 安全开发 软件开发生命周期

27岁了,程序员写给自己的一封信

学习Java的小姐姐

程序员 生活 总结 程序媛 职场回顾

Java技术奇迹

ATGU:阿宝哥

《龙教授私享会职场沟通心法》最佳学习路线(2020最新版)

ATGU:阿宝哥

前端开发必备工具箱

LeanCloud

CSS 性能优化 前端 vscode 工具

ARTS打卡-02

Geek_yansheng25

绝对坦诚:打造团队自我进化能力的最佳姿势

伴鱼技术团队

团队管理 企业文化 团队协作 技术管理 文化

PlantUML 的介绍和使用

Puran

UML PlantUML

架构师训练营 - Lesson Week 1

brave heart

极客大学架构师训练营

2020年5月北京BGP机房网络质量评测报告

BonreeAPM

网络 服务器 存储 机房 主机

程序员未来会成为非常内卷的职业?

非著名程序员

程序员 程序人生 职业 职业规划

ARTS-Week 01

chasel

面试官为什么喜欢拿 Kafka 考验求职者

奈学教育

kafka

cpu分析利器 — async-profiler

小楼

Java cpu profiler

《Oracle Java SE编程自学与面试指南》最佳学习路线图(2020最新版)

ATGU:阿宝哥

为什么你在群里的提的技术问题没人回答?

古时的风筝

程序员 提问的艺术

关于Synchronized锁升级,你该了解这些

学习Java的小姐姐

并发编程 synchronized 轻量级锁 偏向锁 重量级锁

厉害了,SpaceX-API 开源了

非著名程序员

GitHub 程序员 开源项目

createRef、useRef、useMemo对比分析和应用场景

费马

React Hooks useRef useMemo createRef

高德客户端及引擎技术架构演进与思考-InfoQ