【腾讯Bugly干货分享】美团大众点评 Hybrid 化建设

本文来自于腾讯Bugly公众号(weixinBugly),未经做者赞成,请勿转载,原文地址:http://mp.weixin.qq.com/s/rNGD6SotKoO8frmxIU8-xw前端

本期 T 沙龙探讨了移动端热更新相关的话题。因为沙龙时间的限制,本期咱们选取了美团的 Hybrid 化建设、去哪儿的跨平台 ListView 性能优化、微博 Android 端热更新踩过的坑话题。还期待热更新、热修复哪些话题?欢迎留言给咱们。也欢迎报名参加 T 沙龙分享本身开发中的心得。缓存

Hybrid 是移动端热更新最经常使用的手段,限于 App Store 上架审核时间较长,美团大众点评也采起了该方案,欢迎来自美团大众点旅游业务 iOS 负责人吴卓分享**《美团大众点评 酒旅方面 Hybrid 化建设》**。安全


你们好!我是吴卓,很高兴能来到 T 沙龙作这个分享,今天我将从 iOS 的角度跟你们一块儿探讨一下美团点评总体在 Hybrid 建设中作一些事情。性能优化

首先自我介绍一下:服务器

我进入比较早,在 2011 年的 7 月份最先在美团实习。后来又继续出国读研,同时作一名兼职的开发者,在 2013 年的时候,作过 iOS 的独立开发,有不少人把它做为本身的一项事业去作。微信

后来在 2014 年 12 月份从新加入美团,如今是旅游 iOS 的负责人。cookie

我负责的主要是住宿,度假,大交通,整个业务部门成立时间是相对比较晚,像住宿只作了三年,度假作了两年,大交通是去年才开始作的。快速迭代的可以给业务一个很是好的支持。并发

今天的内容主要分红四个部分:模块化

  • 第一简单介绍一下为何咱们要作一个 Hybrid 化这样一个东西。
  • 第二部分是今天的重点部分,会讲一下咱们在 Hybrid 化上作的一些事情。
  • 第三部分会简单回顾一下,咱们作的一些内容和对现有的一些方案作一些对比。
  • 最后,若是你们有问题,能够作一些交流。

1、为何作 Hybrid 化?

第一个问题,咱们为何要作 Hybrid 这个东西,其实刚刚提到整个业务发展很是迅速。在迅速发展中,咱们直接面临了如下两个很是棘手的问题:工具

1. 客户端发版周期长

第一个问题客户端发版周期比较长,相信你们应该有相似的感觉,特别是在一个大公司里面,迭代是相对固定的周期。另外在 iOS 里面若是须要发版还须要 App Store 的审核。

2. 前端资源严重不足

第二个问题是咱们公司一个现状,前端资源严重不足。

解决方案

首先,针对第一个问题,客户端发版周期长,咱们但愿经过一些手段脱离客户端发版限制。

至于第二个问题,咱们但愿把现有的前端和客户端的同窗彻底结合起来,共同开发咱们主要的一个 APP 。

2、Hybrid 化设计

接下来说一下咱们 Hybrid 化总体的设计,整体上咱们是用一种 Native 和 H5 页面强混合的模式

若是在美团上买一个火车票,我不知道有没有同窗买过。其实在美团上买一张火车票,有一部分是 Native 页面,有一些是 H5 页面,有一部分组件是 Native 作的,有一部分组件是 H5 作的。

若是使用这种方式作的话,咱们会遇到如下三个问题:

  1. H5 和 Native 上线时间不一致,如何衔接?
  2. H5 和 Native 之间如何进行通讯?
  3. H5 页面如何接近 Native 的体验?

1. H5 和 Native 上线时间不一致,如何衔接?

第一个问题是说如今的页面里面既有 H5 页面,也有 Native 页面,Native 页面在 App Store 上面的, H5 相对比较灵活的。

因此有个问题,当H5上线以后,客户端须要给H5提供一些跳转的入口,这个跳转的入口提供的应该是在不发版的状况下去给出的,可以经过这种灵活的配置去实现 H5 到 Native 的一个过渡。

美团 APP 现状

咱们来说一下美团 APP 的现状,早在 2014 年美团 APP 其实大部分页面是由 Native 编写的,只有一些活动的展现页面,是用 H5 形式的页面展现的。

为了实现页面之间的解耦合,每一个页面其实会有一个 URL 进行标识,根据每次跳转到一个 Native 页面,如今不少公司都采用相似的方式去作。如今是这样的模式,那怎样让 Native 页面过渡到 H5 呢?

动态路由切换

咱们的方案是对这个跳转去作一些扩展。本质上来讲,客户端这边是从 URL 到 Native 页面的路由表,咱们想办法对跳转的参数作的一些扩展,让他可以支持跳转到 H5 里面,甚至跳转到 URL 的页面。

上图的这个配置可以经过后台进行下发,进行同时的更新,同时为了作这个更新,咱们也为这个路由配置作了一个前端的展现页面。总体来讲经过咱们在原有的这种跳转模式下作了一些动态化的扩展,实现后续客户端发版以后可以从后台下发一些配置。

举一个简单的例子:

在美团 APP 买一个团购的订单,用户须要访问列表页,商家的详情页,建立订单,最后购买成功。

若是咱们有一些新版本的上线没办法支持展现这些新的产品,对一个新的产品作一个 H5 的产品详情和创立订单页面,把这个产品切换到走 H5 的流程最终的客户端发版走这种 H5 的流程。

这样不管是新的用户还有没有升级的老的用户,都及时的访问到咱们最新的产品。

小结

在这儿简单回顾一下,咱们作这个事情的一些设计思路。

刚才说的配置下发只是在特殊状况下作的,由于这种状况是少数,不会天天全部的页面都作这种事情,因此咱们并不会下发整个客户端里面的全部的配置,咱们只是把一些须要更新的内容作一些回应,从后台下发下去。

另一点是说上层的使用方,咱们内部会帮上层调用方,作好全部的相关的工做。

2. H5 和 Native 之间如何进行通讯?

桥协议通讯

第二个问题,前端的 H5 页面和 Native 页面怎么更新,由于他两个是彻底不一样语言开发的,其实这个方案的话咱们通常来讲,把 Native 和 H5 的通讯机制约定为,称之为桥协议

这个桥协议,它是一个双向的通讯方式。绿色部分是讲 NativeJS ,这个是比较直观的,在 WEB 应用里面直接能够调用这个方法。

JS 调用 Native

可是 JS 调用 Native 的方法其实系统没有提供一个很直接的方法,这个地方实际上是咱们须要解决的一个问题。

基本上, JS 调用 Native 本质上就是,给客户端去传递一些消息,传递的消息格式实际上是比较随意的,并且时间只要约定好就能够了。

如今问题就是怎么去传?

这个问题,咱们当时在作的时候,其实调研了一下常规的方案来分析。有三个方案,我具体说一下:

  • 第一个方案是经过 URL 拦截的方法 这个什么意思呢?就是说,对于前端来讲若是 JS 须要给应用传消息,通常会开一个 Server ,会访问一个地址,这个地址他的 Scheme 是一个特殊的 Scheme 。客户端这边会拦截到这种指令格式的 URL 需求,实现一个 JS 到 Native 传递消息的一个过程。

  • 第二个方案叫主动轮询 对于 JS 他须要把给 Native 传递的消息,转化成一个 JSON ,客户端这边通常会开一个线程,每隔一段时间会调 JS 的方法,从这个方法里面把 JS 须要给 Native 传递的消息所有取出来,取出来以后再去作相应的操做。

  • 第三个就是 JSContext 前端能够直接调用客户端本地的方法。

方案对比

咱们简单对比一下这三种方案,第一个方案是 URL 拦截,他的优势不管是哪一种 WebView 都是支持这种方式的,可是它的 URL 拦截延时高一点。第二个方案,主动轮询,能够并发处理多条消息,可是若是在客户端性能开销大,第三个方案是咱们如今正在用的,直接调用,可是他只支持 iOS 7 以上的系统。

模块化拆解

接下来说一个很是重要的一个点,叫模块化拆解,其实像咱们业务,每一个业务,都须要在上面定制本身的桥协议,实际上这个也方便管理。 咱们除了底下红色,刚才讲的消息通信层之外,上面有模块化的管理方式,像客户端这边,右侧是客户端这边有模块的管理模范,各个业务能够本身把本身的模块注册在这个里面,对应的JS层也有底层的封装,左边每个JS对应右边每个模块,会作一些模块化拆解的工做。

开发调试

再说说咱们怎么前端和客户端怎么去开发,调试方式,其实如今方式是说,若是咱们须要新增一个桥协议的话,前端会先准备一个 Demo 页面,把此次须要新加的桥里面放在这个 Demo 页面里面,客户端基于这个 Demo 开发,会给前端打一个模拟器,前端会用这个模拟器安装包,本身完成剩余的链条开发工做,这样的好处是前端和客户端能够同时开发。

小结

简单回顾一下桥协议,桥协议通讯用最简单最直接的方式进行调用,桥协议的实现,最关键一点支持可扩展的能力,开发调试咱们但愿前端和客户段可独立并行开发。

3. H5 页面如何接近 Native 的体验?

第三个问题是指咱们的 H5 页面怎么去接近 Native 的体验,在体验差距上主要两个方面。

页面渲染瓶颈

第一个是前端的页面代码渲染,受限于 JS 的解析效率,以及手机硬件设备的一些性能。其实这个问题从应用开发的角度来讲,是难以解决的。

资源加载缓慢

第二个方面是 H5 页面是从服务器上下发的,客户端的页面在内存里面,页面加载时间上面, H5 页面和 Native 相比是有些差距的,可是这个差距咱们能够经过一些方式弥补的,好比说咱们作了一些资源预加载的方案。

资源预加载方面,其实也不少方式,我主要列举了一些,基本上每种方式咱们都尝试的作了。

第一种方式是说使用 WebView 自身的缓存机制。

若是咱们在 APP 里面访问一个页面,短期内再次访问这个页面的时候,会感受到第二次打开的时候流畅不少,加载速度比第一次的时间要短。

这个就是由于,苹果本身内部 Web 自身会作一些缓存,只要打开过的资源,他都会试着缓存在本地,第二次须要访问的时候他直接从本地读取,可是这个读取实际上是不太稳定的东西,关掉以后,或者说这种缓存以后,系统会自动把它清掉,咱们无法进行控制。

基于这个 WebView 自身的缓存,有一种资源预加载方案,咱们在应用启动的时候能够开一个像素的 WebView ,事先去访问一下咱们经常使用的资源,后续打开页面的时候若是再用到这些资源他就能够从本地获取到,页面加载的时间会短一些。

第二种方案是说,咱们本身去构建,本身管理缓存。

把这些须要预加载的资源放在 APP 里面,他多是预制放进去的,也多是后续下载的。

问题在于前端这些页面怎么去缓存?

两个方案,一个是,前端能够在 H5 打包的时候把里面的资源 URL 进行替换,这样能够直接访问本地的地址。客户端能够拦截到这些网页发出的全部请求作替换。

这个是咱们作的资源预加载的方案,采用的刚才说的第二种方案,每当这个 WebView 发起资源请求的时候,咱们会拦截到这些资源的请求,去本地检查一下咱们的这些静态资源本地离线包有没有。针对本地的缓存文件咱们有些策略可以及时的去更新它。为了安全考虑的话咱们也作了一些预下载和安全包的一些加密的工做。

预加载方案的优点?
  • 第一,咱们拦截了 WebView 里面发出的全部的请求,可是并无替换里面的前端应用的任何代码,前端这套页面代码能够在 APP 内,或者其余的 APP 里面均可以直接访问,他不须要为咱们 APP 作定制化的东西。

  • 第二,这些 URL 请求,他会直接带上先前用户操做所留下的 cookie 而都可以留下来,由于咱们没有更改资源的 URL 地址。

  • 第三,整个前端在用离线包的时候,缓存文件的时候是彻底无感知的,前端只用管写一个本身的页面,客户端会帮他处理好这样一些静态资源预加载的问题,有这个离线包的话,他加载速度会变快不少,没有这些离线包加载速度会慢一些。若是版本不能跟他匹配的话,他的页面也不会发生什么问题。

实践效果

这个是咱们当时作完以后,作完资源预加载以后的一些效果。好比说,这个图里面能够看三个部分,一个是前端部分是没有用资源预加载的下面,深色的部分是有资源预加载的效果,能够看到,若是把有些资源打成离线包放在本地的话,其实他的加载时间是能够缩短不少的。

另一点能够横向的看,其实像一二三,或者是这边的一二三,三个页面,其实本质上这三个页面是一个购买流程人员,须要访问到的路径。

举个例子,要进入第三个页面,他必定会先打开第二个页面,若是他打开第二个页面,他必定会先打开第一个页面。

前置筛选页->车次列表页->车次详情页

因此能够看到,总体的加载时间是不断的缩短的。这个也就符合咱们如今说的 Webview 自身是有一套缓存的。由于访问后面页面的时候有些资源其实在前面的页面已经访问过了,因此整个加载时间是不断递减的。

总结一下今天 Hybrid 化讲的一些东西,包括咱们作的动态路由切换,包括咱们作的自定义桥协议,还有资源预加载的一些方案。

Hybrid vs Native

咱们其实如今整个页面里面既有 Hybrid 页面也有 Native 页面,那么咱们是怎么作区分的?

通常来讲Hybrid的项目通常是用在一些快速迭代试错的地方。另外包括有一些非主流产品的页面,咱们倾向于用 Hybrid 的形式作.

可是像前端购买一些交易环节,特别核心的流程的话,咱们通常状况下会用 Native 的形式去写这些页面,去提高,达到一个极致的用户体验。

3、其余方案对比

最后想对比一下,简单聊一下咱们现有的一些其余方案,固然这些方案,各个其余公司也正在去作。

1. React

第一个是 React 这边,如今作了一些尝试,由于 React 和安卓的平台差别性是比较小,若是安卓端写好代码的话,成本很低,在项目发展初期的话,很好的去应用了这样一种方式,减小成本。可是咱们后面发现,当中也遇到了一些问题,若是其余同窗有解决方案的话也欢迎分享一下。

第一稳定性没有达到一个很好的标准,固然也有多是咱们在使用上还存在一些没有掌握的地方。

第二个问题是人力的问题,我以为可能比技术问题更复杂一点,就是说,其实现有市面上,咱们很难在很短的时间内招到 10 个 iOS 的同窗去作咱们相应的开发。另外咱们即便招到一些人,可是现有的公司里面培养体系,不太适合培养他们往更高层面发展。这个例子在后台比较常见,像咱们如今美团点评是后台绝大部分都是用 Java 去写的,说白一点,就是说 Java 这个东西,仍是比较好招人,好大规模的去扩展去作事的。

2. Weex

Weex 方面,咱们内部有一些调研和学习,可是人力的问题仍是很凸显。

3. 动态模板化

咱们从业务发展的角度来讲,也想得到一些动态性的一些东西。但愿考虑说把有一些局部的模块可以经过后台下发的方式去作。咱们的名字叫动态模板化,可是目前仍是在作的阶段,若是其余同窗有相同的想法的话能够共同作一些分享。

今天的分享先到这儿,谢谢你们!

4、互动问答

Q1:我有一个问题,刚才你说, JS 调用 Native 里面,有一个相似轮询。

吴卓:我那句话意思是说,一次只能拦截到一条消息,若是用轮询的方式的话,能够多条。由于最近应该不多有,最近几期不多有美团的同窗来这儿讲课,若是你们对美团的其余的技术也兴趣的话也能够提出来,我若是知道的话尽可能也跟你们解释一下。

Q2:这里哪个页面是 Hybrid 的?

吴卓:您下的是最近的版本吗?举个例子机票里面选一个国际的城市,你能看到的就是, Hybrid 的页面。国际城市里面切换选择日期的时候,看到的就是 Hybrid 的页面。国际机票的列表也是用 Hybrid 走的。火车票里面之前是用 Hybrid 作的,如今的话,主流改为 Native 作的,固然若是出现一些紧急的状况,咱们经过刚才的切换系统切换到原来的 Hybrid 上。

另外若是您打开交通里面的船票也是 Hybrid 的形式。由于我是作大交通业务的,因此说可能比较熟悉一点,向您推荐的也是咱们的产品。从您点击船票开始后面都是 Hybrid 的页面,固然这个页面里面有一些弹窗,有一些部分是Native作的。

Q3:你以为 Hybrid 的模式和 Native 的模式,您以为哪一种多是将来的发展趋势,技术上。

吴卓:这是一个好问题。我只说一下我我的的观点,不表明公司的观点。首先我以为从一个用户体验的角度来讲,我更但愿把全部页面作成 Native 的,可是若是怎么说呢,我以为好比像 WebView,我刚才说两个问题,一个是说稳定性的问题,还有一我的力资源的问题,若是这两个问题能解决的话,如今属于观望状态,咱们其实能够朝着这方面去作。由于我我的的观点仍是说,全部页面都能尽量的作成 Native 。在作 Hybrid 上,咱们想尽方式让它接近 Native 。

Q4:大家是如何管理 Hybrid 代码更新的呢?

吴卓:离线包的形式确定会增长内存的大小。咱们的团队作增量的更新,以减小这种资源包下载的流量,这是战略空间的问题。 第二个是离线包里面有什么,最主要是一些静态资源文件,包括JS,CSS。基本上H5页面访问,就是在访问一个页面的时候须要加载这些资源咱们均可以从本地给他获取。固然如今不是100%资源的离线化,一是考虑安全的因素,第二战略方面的缘由有些技术无法作离线化。


更多精彩内容欢迎关注bugly的微信公众帐号:

腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的状况以及解决方案。智能合并功能帮助开发同窗把天天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同窗定位到出问题的代码行,实时上报能够在发布后快速的了解应用的质量状况,适配最新的 iOS, Android 官方操做系统,鹅厂的工程师都在使用,快来加入咱们吧!

相关文章
相关标签/搜索