微信扫描登录

Hybrid 方案深入剖析

本篇文章整理自去哪儿网前端资深工程师林洋6月22日在『ITA1024前端技术精英群』里的分享实录:Hybrid 方案深入剖析。

我是去哪儿平台事业部移动组的林洋,今天给大家带来 《去哪儿移动 Hybrid方案深入剖析》。

这个方案是我们团队耗时近两年完成的一体化解决方案。由于我从团队刚成立,就参与到方案的开发,对方案整体以及每个部分都比较熟悉,所以团队派我来给大家做此次分享。有不足之处,请大家包涵。这次分享内容偏介绍性质,有任何问题可以在 Q&A 环节提出,我知无不言。

回顾

移动 Hybrid 方案是什么?

Hybrid 直译是混合动力。移动 Hybrid 方案在移动 App 开发的过程中,使用多种语言、架构进行开发的一种方案。本次分享中,移动Hybrid 方案主要讨论的是以 Web 技术为核心,以 WebView 为载体的开发方案(Adobe Air,RubyMotion,Titanium 甚至 React Native 都算是 Hybrid 方案),使用这类方案开发出的 App 是指介于Web App、Native App这两者之间,兼具『Native App良好用户交互体验的优势』和『Web App开发敏捷迅速的优势』。

Hybrid vs WebApp vs Native App

既然我们将移动 Hybrid 方案定义在『使用 Web 技术』上,那么需要比较 Web App、Hybrid App 和 Native App 这三者之间的差距。

下面的表格中列出了几个重点方面的比较。

enter image description here

其中,体验包括『原生能力』和『性能』两个方面。原生能力指调用联系人信息、接收Push 信息等,而性能主要指渲染效果和App使用时候的流畅程度。

在这里多提一句,很多人认为 Web 技术最大的优势在于跨平台,降低开发成本上。虽然我原来也这样认为,但是我现在的观点转变了:我认为 Web 技术最大的优势在于维护更新上,具体说是热更新上。

虽然现在 Apple 官方缩短了审核时间,但是用户更新 App 的成本也是很高的,很多用户是不愿意主动更新 App 的。在这个移动互联网发展大潮中,一个 idea 晚上线几天,晚被用户用到几天,有时是很致命的。(有人说 Android 可以热更新,没错。但是除非你只关注一个平台,否则单一个平台的热更新意义并不是很大,而且绝大数情况下 iOS 用户的质量比 Android 用户质量要高)而 Web 给开发者的第一印象就是热更新,服务器发布,用户看到的就是新的内容(排除缓存的影响),免除了和软件一样的更新成本问题。

当然,跨平台也是 Web 技术的一大优势,会减少开发成本,而且很容易嵌入微信、微博社交平台。

公司推行移动 Hybrid 方案的原因

去哪儿是一个技术体系非常成熟的互联网企业,客户端开发上的经验也相当深厚,那我们如何在公司内推行移动Hybrid解决方案的呢?痛点!

第一点,就是刚才所说的热更新问题,用户更新成本是每个APP共同的痛点。

第二点,是Size问题,也是iOS平台的。Apple给App一个限定,如果超过100M,用户非WIFI情况下,不能下载更新。这也是一个痛点。

基于这两个痛点,我们的方案在公司内部被广泛使用。

那我们的解决方案究竟是怎样的呢?

当前

去哪儿网跨平台移动开发Hybrid 解决方案 - Hy

Hy 是去哪儿平台移动组出品的跨平台移动开发 Hybrid解决方案,旨在让开发者使用前端技术开发跨平台的移动应用程序。

Hy 从设计之初到现在经历了非常多的变化,战场从小型独立客户端到去哪儿大客户端,业务从零个到近百个。一路走来,Hy 经历了无数考验,并获得了璀璨的成果。现在公司内部80+项目使用了Hy解决方案,并受到了大家的肯定。

enter image description here

Hy方案提供了包括前端框架、客户端框架、离线包机制、开发调试工具、各种支持平台等多方面 的技术和开发支持。下面来说说明一下 Hy 方案的整体架构。

Hy 的架构设计剖析

架构简介:

enter image description here

上图是 Hy 方案的基本架构,它包括:(自顶向下)

  • 前端框架部分,包括UI框架 Yo,负责路由与视图管理的 QApp 以及移动组件库 Kami。
  • 前端与客户端通信桥 —— QunarAPI,它不仅仅连接前端与 Hytive,而且它也适配了微信等客户端。
  • Hy 的 Native 核心框架部分 —— Hytive,类似于 codova,提供插件机制,可以自定义扩展所需的 Native 功能,供前端调用;同时,我们在这个部分做了一些的优化。
  • 插件,基于 Hytive 提供了一些常用的功能,例如分享、登录等功能。
  • 离线资源更新机制,包括 Hytive 更新机制和离线资源服务。 开发工具,适用于移动端,开发、调试工具,方便业务开发。 -发布系统,基于jenkins 的发布系统。
  • 统计系统,包括埋点统计和无埋点统计。

下面详细说明各部分内容。

前端框架: 前端框架部分,主要由三部分组成:

  • UI框架 Yo
  • 负责路由和视图管理等的 SPA 框架 QApp
  • 移动组件库 Kami

Yo 关于,UI 框架 Yo, 瑶姐之前在群里做过分享,在这里再简单说一下,具体的可以去翻阅群分享实录。点此查看实录。

Yo,是一款基于Sass开发的CSS框架,用于快速构建移动项目UI。Yo的设计是以Mobile为基准的,风格偏向于 iOS 的一个多层次纯净的 UI 框架。

enter image description here

QApp QApp ,简洁 、轻量、实用的移动前端开发框架, 统一管理视图的创建 、切换 、通信 、销毁等操作,并辅以 模板引擎 、动画效果 、事件代理 、数据存储等一系列实用性插件和组件, 最终形成一套一体化的移动前端 SPA 解决方案。

QApp 最核心的有三部分:视图管理、路由机制和插件机制。大概的架构图如下:

enter image description here

视图管理和路由,我想大家绝大多数人都比较了解,这里我主要讲一下插件机制。

视图类插件

诸如,模板类的 Hogan,代理事件 Delegated,MVVM类 Avalon。以 Avalon 为例,在视图 render 成功后,自动进行 avalon scan,然后在视图销毁时,销毁 Avalon 的 vm。插件做得更多的是,帮开发者做一些零碎的工作,让开发者更专注业务逻辑。

工具类

诸如,Ajax、Storage等。大家会有疑问,为什么要封装 Ajax?其实,很重要的一点事,在视图销毁时,这个视图中发出的 Ajax 请求需要被 Abort,否则无用请求会继续占用网络资源,同时数据回溯后,视图不存在了,很容易造成异常。虽然只是一个小细节,但是帮业务开发者做狠狠多多小细节后,业务线开发会很顺畅。

全局类

这里要提出 QApp-Hy 这个插件,它是 QApp 为了适配 Hytive 多 WebView 模式而开发的,主要目标是让用户使用 QApp 在浏览器中开发的 SPA 项目可以无缝迁移到App客户端中,这才是解决用户真正的痛点。(详细说明,将在下一个章节。)

Kami Kami 是一款轻量、简单的移动前端组件库。最新的组件使用情况如下:

enter image description here

它具有以下特点:

  • 轻量:Kami中的所有组件都可以独立安装的,并不需要引用大而全的版本。
  • 组件丰富:Kami提供了20+组件,分成了基础组件、业务组件和工具组件,能够满足各种移动端需求。
  • 使用简单:Kami的使用方式方便、简洁,学习成本低。
  • 方便扩展:Kami的组件都提供简单的继承和使用方式,方便进行二次开发和扩展,能更好的适应不同的需求。
  • 平滑升级:通过Kami特有的构建方式,在项目中,能够引用组件的不同版本。在升级的时候,不同组件可以依赖某个基础组件的不同版本,大大减少了回归测试的成本。
  • 良好适配:Kami通过类似皮肤的方式,来使用不同的样式库,比如Yo。同时,Kami也能够通过简单的适配器来适配其他框架,比如QApp。

Hytive + QunarAPI + Plugins:

Hytive 以及桥和插件这一套逻辑,参考 Codova (PhoneGap)实现的,其主要实现的功能是 Native 和 前端 JavaScript 的通信交互。相比于 Codova,我们做了很多修改,其中最重要的优化是 单 WebView 到多 WebView 的改变。

单 WebView 的问题

使用单 WebView,主要会遇到两方面的问题: 性能和异常影响范围。

首先,性能问题,大家众所周知,WebView 渲染效率依赖于内核和其依赖的硬件性能。当你做一个功能非常丰富的应用,尤其是 SPA 或类似的项目时,非常容易造成页面上的 Dom 数过多,占用内存过大,最后导致用户使用时不流畅。

同时,由于所有逻辑都在一个 WebView中,这时当一个逻辑出现异常,可能导致整个逻辑都死掉。举个很简单的例子:弹出一个对话框的时候,蒙层把全部 WebView遮盖,而前端由于代码逻辑的问题,导致对话框上的事件并没有绑上。这种情况下,用户不能进行任何操作,而且用户只能通过杀死 App 的方式解决问题。这个问题虽然是属于业务线的,但是这样的体验对用户并不好,框架层有必要降低异常的影响范围。

为了解决以上几个单 WebView 存在的问题,我们提供了一套比较完善的多 WebView 方案。

多 WebView 方案

Hytive 是给前端操控 WebView 的 API,让前端可以控制新开、关闭 WebView,向后一个或前一个 WebView 传输数据,同时 WebView 也像前端暴露一些事件,来通知前端WebView 所处在的生命周期。

好处有以下几点:

  • 性能优化:便于降低单个 WebView 的内存使用,使显示更流畅
  • 异常隔离:一部分逻辑异常,并不影响整个逻辑
  • 内存管理:当业务逻辑越来越复杂,逻辑深度会越来越多,当用户使用很深的逻辑时,肯有可能会出现内存极限的情况,这种情况系统可以销毁之前的几个WebView,来避免 App 崩溃
  • 便于多业务交叉访问:不同的业务可以很方便的互相访问。

这里,有人会问,多 WebView 会给业务开发造成一定的麻烦,例如说多 WebView 之间的数据交互和生命周期,只能在 App 内进行开发、调试,这样会提高开发成本的。关于这个问题,我将会在『Hy 方案遇到的挑战和应对措施』中详细进行说明。

离线资源更新机制:

从 AppCache 说起 说到离线,肯定要谈到 HTML5 的 AppCache。之前设计离线缓存方案时,调研过 AppCache,发现其非常『不靠谱』。

  • 第一次打开时,才进行缓存。有些核心业务的资源,我需要优先下载或者内置在客户端内。
  • 对 Manifast 更新,会同时重新请求所有的文件,不支持增量更新。
  • 更新后,第二次刷新资源才会被页面采用,会被产品和运营拿刀砍的。
  • 兼容问题和容错机制比较差。各个浏览器实现的程度不一,同时,缓存资源中一个资源更新失败,就有可能引起 AppCache 的异常。

离线资源 离线资源,和缓存资源不同,它更注重的是资源的离线,当用户想用时,不管是有网环境还是离线环境,都可以正常使用。

Hy 方案的离线资源更新机制有以下几个特点:

  • 当进入到项目时,检查是否有更新,如果有,先下载更新再打开项目。
  • 在 WIFI 状态下,打开 APP,会静默下载所有线上离线包。
  • 为了减小更新资源的体积,在传输过程中使用gzip,同时更新离线包时使用差分包(xdiff)。

打包发布时,很根据项目里 index.yaml 的配置文件,进行构建离线包的工作,具体配置文件样例如下:

enter image description here

使用离线资源更新机制的好处

  • 真正的贴近 App 的设计,离线可用,同时具有可以热更新的优点。
  • 加载更快,避免一些网络传输导致的用户体验上的损失。
  • 有效避免某些无良运营商的注入。

开发工具:

工欲善其事,必先利其器。除了技术、框架层面的,我们还围绕着 Hy方案提供了一些非常有用的开发工具,例如最基本的代码打包、项目构建、热刷新,还有比较实用的本地 DNS 服务,代理服务,iOS开发包自助Build 服务,以及 Iconfont 平台、Source 平台等支持类平台服务。

Hy 方案遇到的挑战和应对措施

Hy 方案从开始至今,快两年的时间了,期间遇到了不少挑战。我列举了三个案例分享给大家。

SPA 适配多 WebView

上面提出,单 WebView 方式的问题,同时 Hytive 支持多 WebView 的形式,那么业务开发的 SPA 页面怎么能不提高成本地运行到App 客户端里呢?

首先,可以看一下 QApp 视图的生命周期。

enter image description here

除去模板加载和渲染,QApp 视图的生命周期的设计完全是参考 Naitve 的 View 或 Activity 的,与此同时,Hytive的 WebView 也提供了一套近似的生命周期逻辑,所以 QApp 的视图和 Hytive 的 WebView 基本上可以无缝对接。

由此,QApp-Hy 的做法是判断环境后,如果是 Hytive,当路由转换时,通过 Bridge 的桥,新打开一个 WebView 来显示新的视图,并通过 Bridge 提供的数据接口互相通信。 可以说 QApp-Hy 是业务方选择 QApp 的一个重要原因。业务方的开发者,只需在Chrome 进行传统的 SPA 开发,然后开发的项目就能正常、流畅的运行在 App 客户端内,这才是真正的降低了业务的开发成本。

从这点可以看出,Hy 方案是真正为业务着想的。

第三方页面嵌入

Hybrid 的形式,很方便第三方业务的嵌入。当我们的方案受到公司大部分业务线的认可后,一些业务线提出嵌入第三方页面的需求。

这时会遇到两个问题:

  • 交互一致性问题
  • 安全性问题

所以,Hy 参考微信的方式向业务方提供一个新的不限制域名的 WebView 容器,通过 Bridge 提供分享、获取网络类型、获取地理位置、扫一扫等通用的功能。一方面保证了原有 Hy WebView 容易功能和安全性的同时,也方便了第三方业务的接入。

CrossWalk 的抉择

谈到 Hybrid,谈到 Codova ,不能不谈 Intel 的 CrossWalk。Android 从 4.4 开始使用 chromium 作为系统浏览器内核,而之前的版本则是一个蹩脚的Android WebKit浏览器内核,版本越低性能越差,在加上国产厂商各种胡乱修改浏览器内核,导致 AndroidWebView 环境很差。

虽说未来 Android 4.4 以上的系统会占据更多市场份额,但目前4.0 ~ 4.3 这部分现在还占优很大市场份额。(4.0 以下可以不考虑了)而 Crosswalk 作为一个性能超强的可嵌入内核,好像使用它会让前端开发变得很完美,不用再进行各种兼容。

事实上,CrossWalk 基本上可以满足各种要求,但是有两个很重要的问题,让人比较纠结:

第一是Size,CrossWalk 有 20M +,其简约版也有 10M + 。(去哪儿 Android 客户端一共 20+ M)加入 CrossWalk,致使 App 的体积成倍扩大,是公司难以忍受的。

第二是稳定性。在一些机器上,尤其是一些国产机器上,使用 CrossWalk 会出现闪屏、黑屏等情况,虽然大部分都是定制惹的祸,但是问题是存在的,而且是可见的。

在这样的前提下,Hy 方案提供了一个配合黑白名单的热更新方案:在用户 Wifi 情况下,使用 App 时,向服务器请求下载 CrossWalk,如果此机型不在黑名单中(没有稳定性问题),则 App 会下载 CrossWalk,并在下次启动时使用。

这样的解决方案,既有效利用了 Crosswork 的优势,同时规避了它的一些问题。当然这种情况下,前端并没有降低开发成本(仍旧要兼容各种机型),但是用户体验会提高很多。 (注,CrossWalk 不只只是为了解决老版本原生浏览器性能问题而升的,像最近在iWeb分享上,CrossWalk 支持了 WebVR 等一些新标准,让人感觉眼前一亮。)

Hy 架构大概说到这里,最后副一张Hy架构的思维导图。

enter image description here

展望

Hy 2.0 的大迈步

Hy 从开始开发到现在,已经快两年了,在服务业务的同时,业务也给我们反馈了很多颇有建设性的意见。根据这些意见并参考业界其他框架、方案的设计,在加上团队成员的不断探索和思考,我们对 Hy 2.0 有个新的展望。

  • 整合概念,使概念更容易被开发者理解。
  • 前端基于 ReactJS 构建。
  • 加强服务端路由支持。
  • 开发工具更轻便、更易用。
  • 客户端框架更稳定。
  • 辅助开发平台更完善。

相爱 or 相杀 ? Hy VS QRN

从去年开始,React Native 开始火遍业界,我们团队也提供了基于 RN 的解决方案 —— QRN。

Qunar React Native 是 Qunar 基于 React Native 深度定制的移动平台框架,旨在让移动开发者使用 JavaScript 进行移动平台的高效开发。它拥有极高的代码复用率、丰富的 API 扩展、更快的加载速度、完善的部署系统等。

这套解决方案也已经在去哪儿大客户端内上线了,现在有将近10个项目团队使用这套解决方案来进行业务开发。

这两套并行的方案是什么关系?是否存在竞争?

首先,关系是互相促进,虽然开发框架的同一个团队,但毕竟是两个项目,两个项目之间可以时常作比较,做得不好的地方可以尽可能地优化,让其变得更好。

其次,两个解决方案针对的开发者是不同的。Hy 主要针对的是前端开发者,而 QRN 由于公司人员的结构,它同时要满足前端和客户端开发者的需求。毕竟 RN 有一定的学习成本,而且高于移动 Web 开发。

最后,开发体验。RN 之所以火爆的原因,比纯 Native 开发的开发体验优秀很多,至少不用每次修改完代码必须打包运行才能看到效果。不过相比于成型数年的前端开发体系来说,RN的开发体验并不是想象中的那么好。而诸如 Babel 打包这些黑盒,有时候出问题并不能很快定位。

所以,Hy 和 QRN 并不冲突,一个是纯 Web 的开发方式,拥有 Web 的良好开发体验,但存在一定的性能和壁垒;一个是用前端语言构建NativeApp,拥有性能优势和先进的开发思想,但学习成本和开发体验上有一定的差距。选择用哪套方案,由业务开发者来决定,我们更多的是把方案完善好,让业务方不管使用那套方案都可以顺畅的完成开发。

总结

当前移动前端热度非常高,之前有广泛被采用的 Hybrid 方案,而现在 React Native 又火遍全球,同时也出现了像 Weex 这样的原理与 React Native 类似但针对于前端有很好的开发体验的框架,所以选择好适合自身的解决方案还是很重要的。

我所在的团队按照公司的需求,提供了一套很完整的 Hybrid 解决方案的同时,也提供了 QRN 以便公司更多开发者可以参与进来。

本次分享主要阐述了去哪儿 Hybrid 解决方案 —— Hy 的架构和一些开发实践上的经验,希望能给大家提供些许帮助。