@qinyun
2019-01-17T18:52:57.000000Z
字数 5747
阅读 1526
未分类
近年来,移动互联网应用有着爆发式的增长,同质化APP层出不穷,人们对于产品体验的要求越来越高,渲染迟缓、交互卡顿的单体 Web APP 已经无法满足现有用户苛刻的使用标准;与此同时,井喷式的业务需求迫使 iOS、Android 两个移动平台不断提升迭代开发速度,缩短版本发布周期;如何既能利用 Web 门槛低、轻量级、跨平台开发的优势,又能尽可能最大化屏蔽其现存缺点成了大前端融合领域攻克的重点。
本文借用主流移动跨平台开发方案,向大家介绍移动平台开发的演变之路。
移动应用开发领域发展至今已基本被 Android、iOS 两大平台统治,每个平台仍在不断发展完善、壮大自己的生态系统;对开发者而言每个平台更像是一个巨大的 SDK,为我们抹平了设备硬件、系统内核所带来的差异,统一了平台设计、开发方式。
Figure 1 移动开发平台概览
为了追求极致的开发效率、降低研发成本,早期的开发者不断尝试利用新技术突破平台所带来的约束,PhoneGap 技术(旨在让早期的Web-App Written once, run everywhere )的出现让开发者们看到了 Hybrid-App 的雏形。
PhoneGap 技术基于WebView引擎中的 JS Core 解释器,其核心是 Cordova JavaScript类库,这层JavaScript Plugin抹平了不同平台间的差异,为Web 与 Native 交互提供了统一的抽象接口及完善的调用机制,其本质是将不同平台打造为一个接口统一的Web壳资源平台:UI渲染依赖平台 Web Render 处理,统一使用 HTML+CSS 绘制;交互逻辑使用JS Core这种方式在早期大大降低了开发成本、同时也缓解了早期特定移动平台开发人员稀缺的问题,早期定义的 Hybrid-App 更像是基于移动平台开发的 Web App。
Figure 2 基于PhoneGap开发的移动APP
伴随业务规模的发展,人们发现这种方式虽然高效,但是用户体验却是一团糟;虽然实现了跨平台开发,但又被有限的插件资源所限制;移动开发领域初期,系统平台众多,一系兼容处理让整个框架变得臃肿,这令原本就性能堪忧的框架更是捉襟见肘。随着前端技术的进步,开发者们也在不断打磨Cordova框架:提升整体加载性能、增强插件扩展灵活性,从大刀阔斧到精雕细琢,Cordova生态系统逐渐完善, 众多公司也纷纷开始围绕 Cordova 及一些主流的前端框架打造自己的专属移动开发平台,Hybrid-App也从青涩步入成熟。
Figure 3 基于Cordova Plugins 的主流Hybrid APP框架
这里不得不提到影响了近几年前端设计思想的UI框架React.js,其设计初衷是优化web在移动端的渲染性能、改变传统的UI开发方式:
组件的概念 - React基于UI组件构建视图,每个组件负责维护自己的(State)展示状态,利用简单的UI组件创建复杂的UI;利用组件组合后形成的单向数据流,根据 State 的变化来刷新UI展示;同时推出了更便于组件化开发的 JSX(JS 语法糖) 语言。
Visual DOM - React一个颠覆性的创新就是引入了二进制 Visual DOM 树,其本质可以理解为在 JS 和 DOM 之间做了一个缓冲层用于保存 Virtual DOM 树,UI状态变化时只比较新旧 Visual DOM,通过 Diff 算法找出节点差异,然后进行真实 DOM 操作。因为操作HTML DOM 是非常耗费系统资源的,通过这种方式可以保证以最小代价刷新UI。
轻量级的UI框架 - 可以和其他前端框架结合使用,React.js只是单纯的UI框架,也就是常说的 MVC 框架中的 View 层,它借用了响应编程模式的特点来简化Web视图的创建过程;Model层 和 Controller层的缺失催生出了 Flux 和 Redux(Redux可以视为 Flux 框架的精简版) 框架。
这里仅以使用比较广泛、知名度更高的 Redux 框架来介绍,Redux框架的核心理念是严格的单向数据流,只能通过 dispatch(Action) 的方式修改Store数据(Store的概念源自MVCS框架,Store 不仅仅是 Model 的概念,理解为前端中的DB形式更为贴切),其流程可以简单描述为:View -> Action -> Reducer(logic process) -> Store(change/write/delete state)。
Redux的设计理念是不是看上去和React.js不谋而合?再加上 Redux 社区还基于异步流扩展了很多 Extensions 插件(redux-trunk、redux-promise、redux-saga、redux-observable 等),所以很多厂商纷纷选用 React+Redux 作为自己的 Web 支撑框架。
至此,也就形成了业内主流的Hybrid-App 框架 Cordova+React+Redux,但是由于Web有着先天的局限性,前端框架只是从架构设计、算法层面对性能进行优化,仍然无法解决根本问题:
首次渲染效率及白屏问题
单线程的状态分发机制,无法满足复杂用户交互场景(滑动,拖动手势)
伴随着业务规模持续增长的 js plugin,基于单Web页面的注入机制,无法有效控制内存增长
React.js 这种依托于算法优化渲染效率前端框架,也有着无法回避的缺陷:
首次创建 Virtual DOM 树的耗时相当于延迟了首屏渲染时间
每次 State 变化都会生产全量 Virtual DOM 树,和上一次结果做diff,这其实是一次算法执行时间与Real DOM 操作时间的博弈
需要编写大量的闭包函数(Redux 也有同样的缺陷)
随着业务爆发式的增长、交互复杂度提升、数据请求不断增多,如果要 Redux 承载整个App或大部分关联Web的数据处理已经非常困难:
Store中存放的冗余数据越来越多,维护了多个 Web 页面的组件状态
直接在 reducer 中操作View 与 Model,几层 reducer 之后很难明确 Model 已经被加工成何种形式
一直会有下一个基于 Redux 的改良封装 Extensions
异步、同步相互依赖场景,复杂UI交互,恐怕大部分精力都在考虑 reducers 怎么拆分了
不可否定的是,React 和 Redux 是伟大的框架,他们设计思想、核心理念对后续移动领域的发展有着深刻的影响;移动互联网技术的发展反而放大了它们的先天缺陷,这也加快了 Hybrid-App 的进化速度。
在W3C制定HTML5标准之初,FB的创始人扎克伯格就曾口出狂言要用HTML5技术统一移动端,无奈宣告最终押注失败,随后 React、Redux Web框架的相继推出表明了他们并未真正放弃,这也为2015年FaceBook发布 React Native 框架买下了伏笔。
一心想统一移动端开发的FaceBook在2015年宣布了只用 JS 语言开发 Native 应用的框架 React Native(后文称:RN),并提出了新的口号:Learn once write anywhere,新框架强调的是UI绘制、交互逻辑思想、开发方式的统一,与 Cordova 不同的是 RN 将 JS 中定义的组件标签都转义成了原生对应的 UI组件,直接抛弃了 WebKit 中渲染、绘制功能,全部使用 Native 资源,其核心思想是基于JavaScript 虚拟机将 JSX 编写的组件映射为Native UI组件。由于RN技术天生就引用了自家的 React.js 技术框架又有整合了Native平台UI组件,在发布之初让广大前端开发者看到了新的希望。
不同平台的 JS 虚拟机为 RN 提供运行时 JS Context 环境,其中注入了 RN 转义 Native UI组件的接口,相较于传统的 Cordova 形式的 Hybrid-APP,不深究细节的话,可以认为 RN 使用了原生 UI 组件完美替换了Web Core中的 H5 + CSS 的绘制框架。
Figure 4 React Native 跨平台开发框架
由于使用了原生UI组件,其渲染速度和UI流畅度有了质的飞越,前期很多 Web 页面无法支持的效果也可以使用 RN 来实现;只使用 JS/JSX 开发,兼容Web React.js、Redux.js 等主流框架,RN自身也实现了大部分UI组件的集成工作,再借助活跃的社区,开发效率相比于原有的 Native+Web 形式的 Hybrid-App 有了显著提升。
虽然RN在发布早期备受关注,甚至一些互联网企业已经发布了RN的商业化平台,但是业内仍然出现了“RN - 由入门到放弃”的声音,究其原因,主要可以归结为以下几类:
无法完全抹平跨平台JS Engine的差异性,JavaScript Core 的不一致性,RN 的 Android版本仍然不支持 ES6 的 JSC
发布快四年之久,仍为 0.x 版本,还不能满足 1.0 版本的稳定性(近期Facebook又在对RN进行大规模重构)
RN社区开源库质量参差不齐,很容易跳进坑里
很多基础框架的库还是不支持 RN,需要自己封装
学习成本高,为了输出一个稳定的版本既要熟悉iOS平台特性又要兼顾Android平台兼容性
启动时间长,向单一 JSC 中注入一段庞大的 js 插件仍然需要很长时间,即便只是注入基础插件库
RN框架每一次版本升级所带来的接口向下兼容问题
JS是单线程的解释性语言,手势、动画仍然是无法解决的痛点
Android 9.0 已经开始着手对插件进行主动封堵,这也会给各种形式 Hybrid 带来一定影响
Facebook起初正是考虑到不同浏览器 WebKit 内核的差异性以及web view 所造成的内存、性能损耗,所以才决定仅仅基于JS VM,只使用单一的 JavaScript语言来完成跨平台开发的统一,却忽视了不同平台系统、版本所带来的差异;还有就是JS解释性语言先天的单线程执行所带来的硬伤,始终无法屏蔽 JS VM 的效率损耗;有没有哪种框架可以避免这种硬伤,又能满足跨平台开发的需求呢?搅局者 Flutter 出现了。
Google这种以创新为本的公司当然不满足于RN这种带有瑕疵的框架,Google开启了 Flutter 框架的开发,至今已发布 1.0 Release 版本。Flutter从设计初期就选用可编译成机器码的Dart语言开发并且决定将UI组件和渲染器从平台移动到应用层中,直接避免了由 JavaScript Bridge 引起的性能问题并最大可能降低了系统平台的差异。
Figure 5 Flutter 跨平台开发框架
Flutter实际上是在已有移动平台中搭建了一套独立的开发系统,它也是至今为止唯一提供响应式视图而不需要桥接器的移动SDK,Flutter唯一要求是系统提供的 Canvas 、访问事件(触摸、定时器等)和服务(位置、相机等)。其整体架构设计可以总结为一下几点:
1.一切皆为Widget,这与React中一切皆为组件类似,不过 Widget 承载的定义更广泛一些;
2.使用 Google 自家的 Dart 语言开发 Flutter Widget,Dart语言的主要特性就是可编译为机器码,无需依赖桥接器;
3.Flutter框架在设计上引入了分层结构,每一层都简历在前一层之上,并且开源全部框架代码(个人认为在Preview版本全部开源并不利于生态发展);
4.Flutter直接基于 GPU引擎绘制,抛弃系统 UI 组件(原文引用:借助可移植的 GPU 加速的渲染引擎以及高性能本地 ARM 代码运行时以达到跨设备跨平台的高质量用户体验);
5.Debug Mode支持 hot reload,减少开发阶段编译、调试时间。
Flutter 框架因为直接基于 Canvas 开发,这也显著降低了在旧版本操作系统上进行兼容性测试的需求;Dart 也拥有和 NPM 类似的软件包仓库,这些软件包也可以扩展当前应用的能力。想为开发者打造一套独立的开发框架,当然你也会猜测到,Flutter框架不会太完美:
Dart 语言的嵌套地狱
由于 Dart 编译器使用了tree shaking 等技术,也因而在Flutter中禁止了Dart支持的反射特性
Flutter无法使用 iOS、Android 自带的设计样式
将 Flutter 开发框架植入现有iOS、Android开发工程要做很多适配工作
完全开源的 preview 框架让人担忧其框架生态的健康发展
涨乐APP受限于现有架构和业务需求,对于RN、Flutter等框架保持谨慎的态度。我们当前采用 Hybrid 形式进行开发,交互复杂、安全要求较高、内存资源占用高的业务(如:行情、交易、活体检测、双向视频等)均由Native开发;场景比较单一、样式频繁变更、交互简单的需求页面则使用 Web 开发。
涨乐APP中现有的Web框架并未采用 jsBridge 注入的方式,而是仿造 Spring 的设计思路,将现有 Native APP 打造为了一个 Local Server 平台,将Native功能打造为一个个独立的 Service 组件,仿造 Rest 接口统一 Native -> Service、Web -> Service 调用协议;Web 开发人员基于 Ajax 调用不同的 Service 组件,LocalServer负责分发不同的 Service。
涨乐APP基于平台优势,拦截了现有 Web 资源加载、请求协议,扩展了 Web 资源的能力及生命周期,避免了传输重复资源耗时;也正是因为有了 Web 拦截机制,涨乐APP可以在 Web容器 初始化的同时进行资源下载操作,这样有效缩短了先初始化容器再下载资源的时间损耗。
相比如 Cordova 方式的优点:
利用现有移动平台特点,牺牲Service调用分发时间换取对内存空间,尽可能减少注入 js插件体积
仿Spring框架打造的 Local Server 平台,基于 Service 打造 Native 支撑
Web 资源加载协议拦截机制,避免冗余资源文件传输,加速
本文借用几个主流框架简单介绍了大前端跨端技术框架的发展线路,随着移动应用开发技术的不断发展、成熟,最终会形成一套稳定、统一的跨平台开发体系; 开发者对于web容器增强、业务插件化、虚拟运行环境等技术框架的不断深耕、雕琢也都在推进大前端技术朝着一个统一的方向前进 -- 多端融合。我们只能通过不断的技术积累、输出,才能追赶上大前端变革的浪潮,让业务更好地依托技术为用户提供更优质的产品体验。