混合开发/跨端开发实践
原生与Web的不足
原生应用程序在我们的日常生活中颇受欢迎,但它们在很多层面上也有改善的空间。
Web是能够避免这些问题的一个理想平台,但到目前为止,它仍然不够完美。
-
与原生应用相比,Web应用很难利用系统提供的功能。此外Web应用程序的性能很难媲美或超过功能类似的原生应用程序。
-
在移动设备上,用户经常要获取浏览器之外的服务或内容;显然,他们希望系统中的所有应用程序在用户帐户、登录状态和用户交互上保持一致。此外,有时用户可能希望与应用程序共享某些数据(如果他们真的信任它),但是一些经常请求的信息(例如当前设备的个人移动电话号码或联系人列表)很难在Web应用上提供许可。
混合开发
WebView
Cordova的基础是html和js运行在webview容器里面,通过Cordova提供的接口与硬件通讯;所以它的效率天生收到限制,而且也受到了各个厂商对webkit内核的好坏;比如之前基于国产某Cloud的程序,在华为手机上显示就不正常,花费了不少精力修改;
RN的效率由于是将View编译成了原生View,所以效率上要比基于Cordova的HTML5高很多,但是它也有效率问题,RN的渲染机制是基于前端框架的考虑,复杂的UI渲染是需要依赖多个view叠加.比如我们渲染一个复杂的ListView,每一个小的控件,都是一个native的view,然后相互组合叠加.想想此时如果我们的list再需要滑动刷新,会有多少个对象需要渲染.所以也就有了前面所说的RN的列表方案不友好;
Flutter吸收了前两者的教训之后,在渲染技术上,选择了自己实现(GDI),由于有更好的可控性,使用了新的语言Dart,避免了RN的那种通过桥接器与Javascript通讯导致效率低下的问题,所以在性能方面比RN更高一筹;有经验的开发者可以打开Android手机开发者选项里面的显示边界布局,发现Flutter的布局是一个整体.说明Flutter的渲染没用使用原生控件进行渲染
HTML5于2007年在W3C立项,与iPhone发布同年。乔布斯曾期待HTML5能帮助iPhone打造起应用生态系统。但HTML5的发展速度并不如预期,它虽然成功地实现了打破IE+Flash垄断局面的目标,却没有达到承载优秀的移动互联网体验的地步。
于是在iPhone站稳脚跟后,发布了自己的App Store,开启了移动互联网的原生应用时代。随后的Android,本来是基于Linux的OS,与之同期的MeeGo等竞争对手采用C + HTML5的双模应用生态策略,然而C的开发难度太大,HTML5体验又不行。Android依靠Java技术生态,在竞争中脱颖而出。于是在移动互联网初期,应用生态被定了基调 —— 原生开发。
依赖于像APICloud这样的第三方工具,开发者是可以较好地屏蔽底层开发细节;而在React Native与Flutter开发中,我们仍需要去改造或实现许多的原生代码。
软件是关于如何操作大量晶体管和电路(两者统称为硬件)的指令的集合。直接运行在硬件上的原始指令对我们人类来说是几乎无法理解的,特别是考虑到当今计算机的复杂性和规模。
要使得软件可以理解和操作的话,计算机科学家将其划分为多个层,这些层均是由框架构成的,每个框架都运行在另一个框架之上。在所有框架中,越接近硬件的框架,我们就说它更“原生”。
通常,更原生的框架中的程序能够获取更多的硬件功能,以及使用硬件更加自由。由于在不同语言之间进行模拟和翻译的开销较低,通常它的运行效率更高。但现实是残酷的,它的代码通常更难编写和理解。
另一方面,对于原生化更少的框架来说,通常编写代码更为简单。编码语言也更容易理解和简洁(需要的代码少)。它的词汇更接近与我们人类的自然语言。它不需要我们十分了解硬件的构成以及它在幕后的工作方式。还有一个额外的好处,原生化较少的框架中的程序通常更具可移植性,程序可以在完全不同的硬件平台上运行而无需修改,因为它的词汇和底层概念不包含任何特定于原始硬件的内容。但是,这一切便利的代码就是通常会牺牲一些效率和自由度。
首先是原生阵营,例如安卓的Java/Kotlin和IOS的Objective-C/Swift 。此阵营中的应用速度都很快,并且可以使用丰富的硬件功能。用户界面是针对目标平台(安卓或IOS)的定制的,因此使用起来是流畅且愉悦的。但是,所有这些好处都被限制在一个平台上了。要开发应用的话,需要学习不同的框架。
Cordova/PhoneGap和Ionic为代表的。这些框架可以让Web开发人员使用他们已经具备的HTML、CSS和JavaScript技能来开发应用。这些应用可以同时运行在安卓和IOS平台上(还可以有更多平台)。但是,相比于原生应用,这类应用会没有那么流畅,能访问的硬件功能也有限。最重要的是,这些应用的用户界面太烂了!因为这些框架使用的WebView来渲染UI,所以我们将其称之为WebView框架。
React Native直接使用了原生UI组件,而WebView框架是使用HTML/CSS的Web UI来模拟原生UI 。
软件是关于如何操作大量晶体管和电路(两者统称为硬件)的指令的集合。直接运行在硬件上的原始指令对我们人类来说是几乎无法理解的,特别是考虑到当今计算机的复杂性和规模。
要使得软件可以理解和操作的话,计算机科学家将其划分为多个层,这些层均是由框架构成的,每个框架都运行在另一个框架之上。在所有框架中,越接近硬件的框架,我们就说它更“原生”。
通常,更原生的框架中的程序能够获取更多的硬件功能,以及使用硬件更加自由。由于在不同语言之间进行模拟和翻译的开销较低,通常它的运行效率更高。但现实是残酷的,它的代码通常更难编写和理解。
另一方面,对于原生化更少的框架来说,通常编写代码更为简单。编码语言也更容易理解和简洁(需要的代码少)。它的词汇更接近与我们人类的自然语言。它不需要我们十分了解硬件的构成以及它在幕后的工作方式。还有一个额外的好处,原生化较少的框架中的程序通常更具可移植性,程序可以在完全不同的硬件平台上运行而无需修改,因为它的词汇和底层概念不包含任何特定于原始硬件的内容。但是,这一切便利的代码就是通常会牺牲一些效率和自由度。
首先是原生阵营,例如安卓的Java/Kotlin和IOS的Objective-C/Swift 。此阵营中的应用速度都很快,并且可以使用丰富的硬件功能。用户界面是针对目标平台(安卓或IOS)的定制的,因此使用起来是流畅且愉悦的。但是,所有这些好处都被限制在一个平台上了。要开发应用的话,需要学习不同的框架。
Cordova/PhoneGap和Ionic为代表的。这些框架可以让Web开发人员使用他们已经具备的HTML、CSS和JavaScript技能来开发应用。这些应用可以同时运行在安卓和IOS平台上(还可以有更多平台)。但是,相比于原生应用,这类应用会没有那么流畅,能访问的硬件功能也有限。最重要的是,这些应用的用户界面太烂了!因为这些框架使用的WebView来渲染UI,所以我们将其称之为WebView框架。
原生桥接
React Native直接使用了原生UI组件,而WebView框架是使用HTML/CSS的Web UI来模拟原生UI 。
小程序
小程序是一种新的移动应用程序格式,是一种依赖Web技术(尤其是CSS和Javascript),但也集成了原生应用程序功能的混合解决方案。小程序的出现有着明显的商业诉求,因为马太效应,一些超大流量的App诞生了。这些大流量App集成了许多功能,但显然公司再多员工,也无法所有功能全是自己弄,于是产生小程序这种“外包”的手段。
它的一些特性有助于填补Web和原生平台之间的鸿沟:它不需要安装;具备多个Web视图以提高性能;它提供了一些通过原生路径访问操作系统功能或数据的机制;它的内容通常更值得信赖,因为应用程序需要由平台验证;小程序可以分发到多个小程序平台(Web、原生应用,甚至是OS)。这些平台还为小程序提供了入口,帮助用户轻松找到所需的应用。
小程序是国内前端技术的一次厚积薄发:底层运行的迷你React的虚拟DOM,内置组件是使用Web Component,API来源于Hybird的桥方法,打包使用webpack,调试台是Chrome console的简化版,WXML、WXSS的语法高亮也应该是webpack或VS Code的插件,模块机制是Node.js的CommonJS……其中最值得一提的是微信开发者工具,以后开发者工具成了各种小程序/快应用的标配。
但微信小程序一开始的复用能力非常弱,没有类继承,不能使用npm,不支持Less、Sass,因此基于它的转译框架就应运而生。第一代转译框架是wept、WePY、mpvue,它们无一例外是Vue风格的。因为WXML的模板指令与Vue非常相似,只是改一下就能兼容。当时也出现了一个MINA的框架,听说是微信团队开发的,可以单独架起Node.js后端,让小程序运于浏览器中,方便做单元测试。
第一代转译框架主要是基于Template标签实现组件机制,自定义组件机制是以后的事了。这就造成了利用第一代转译框架编写的小程序项目很难升级。那时候是个人开发者的天堂,这些框架都是某一大牛独力开发的。
第二代转译框架是大公司主导的,因为需要兼容的小程序越来越多,百度、支付宝、字节跳动、小米、华为等公司都推出自己的小程序和快应用。个人开发者很难凭个人力量去开发转译框架,这时候各大团队纷纷推出自己的轮子:如京东的Taro、滴滴的Chameleon网易的Megalo、去哪儿网的nanachi、百度的Okam等。
在这个时期,Angular显然落伍了,一是Angular升级太快,国内的高手还没有消化好,新一版的Angular又发布了。二是国内缺乏迷你Angular的轮子,导致庞大的Angular无法塞进小程序中。
国外谷歌发布了Flutter跨平台转译框架,但是它的编写语言是Dart,它也无法跨界到小程序中。
未来不仅国内一线巨头争夺小程序,二三线的巨头也可能会加入小程序的混战中,例如有人称360也在打造自己的小程序平台。小程序这种新的流量变现模式深刻地影响了国内的互联网布局。
终端开发离不开三大要素——界面表现(结构、外观)层、逻辑处理层与系统接口层(网络、存储与媒体等)。
开发者编写代码时在初始化阶段(生命周期)调用“界面表现层”界面模型的接口绘制界面,当用户触摸界面时,“界面表现层”将事件发送给用户“逻辑处理层”,后者经过条件判断再处理并反馈到用户界面,处理过程可能需要调用“系统接口层”,反馈过程需要调用“界面表现层”的接口。常规的终端开发架构模式下,无论是Web端、Android端还是iOS端的项目开发,都强依赖各端的环境接口,特别是依赖界面相关模型设计。iOS系统下绘制界面基于Objective-C语言环境下的UIKit框架;Android系统下用户绘制界面基于Java语言环境,由LayoutInflater处理XML结构层次树;Web端使用DOM模型和CSS来描述绘制界面。
MVVM中的关键是它通过ViewModel这一层将界面和逻辑层彻底隔离开来,负责关联界面表现和逻辑处理层的响应事件(update/notify)关系,这一“隔离层”上下通信足够规范、足够纯净单一。Model进行逻辑处理是纯业务响应逻辑,任何一种语言都可以实现,你可以用Android的Java,也可以用iOS的Objective-C。
React Native、Weex与快应用的MVVM,开发者编写的代码在虚拟机(V8、JavaScriptCore)里面运行,虚拟机容器里面包含扩展的系统基础接口。运行时,将描述界面的数据(主要是CSS+DSL所描述内容)通过通信层传递给Android、iOS端的渲染引擎,用户触摸界面时,通过通信层传递给虚拟机里面的业务处理代码,业务处理代码可能调用网络、储存与媒体等接口,最后再次反馈到界面。
Flutter和RN的最大区别在于将“JavascriptCore/V8+JS”替换成“C++实现的engine+Dart实现的Framework+静态类型Dart+编译成机器码”。
小程序本质上和Weex、React Native的设计思路基本一样,最大区别在于前者还是用浏览器WebView做渲染引擎,而后者是单独实现了渲染引擎(所以大量的CSS布局模型不支持)。
Links