注:本文为转载文章,部份内容参考移动端跨平台开发的深度解析,并作了精简和加工。前端
移动跨平台开发一直是移动开发者和前端开发者追求的的话题,从早期的cordova、ionic,到现在的react native、weex、kotlin native和flutter等,能够说现在的跨平台框架可谓百花齐放,很有一股推倒原生开发者的势头。vue
若是要对目前的跨平台的方案进行一个总结,大体能够分为如下几个流派: JavaScript流派:这一流派中,最明显的特征是使用JavaScript做为编程语言,react native、weex均属于这一流派。和其余跨平台方案相比,JavaScript在跨平台开发中,使用者最多,大有“一统天下”的趋势。 VM虚拟机:与其余方案不一样,kotlin提供的kotlin-native技术拥有本身的VM,能够同时支持Android、iOS 和 Web 开发。 Flutter:Futter是Google开源的移动跨平台UI框架,使用的是Google本身的Dart编程语言,因为是Google推出的产品,于是也受到不少开发者的喜好。node
不过,综合对比开发现,目前最火的跨平台开发方案,特别是已经商用的跨平台开发框架中,react native无疑是老大,其次是Weex(毕竟是阿里的产品),最后多是最近才火起来的Flutter。react
曾经,React Native的口号是“Learn once, write anywhere”,这句话表明了FaceBook对React Native设计的初衷:学习 react ,同时掌握 web 与 app 两种开发技能。android
借助FaceBook旗下的React的设计模式 , React Native使用的UI渲染、动画效果、网络请求等会转换成原生端的实现。也就是说,开发者编写的js代码,经过 react native 的中间层(JavaScriptCore)转化为原生控件和操做,这就最大程度的接近原生应用的用户体验,并提升了开发的效率。webpack
React Native的跨平台是实现主要由三层构成,其中 C++ 实现的动态连结库(.so),做为中间适配层桥接,实现了js端与原生端的双向通讯交互。ios
这里最主要是封装了 JavaScriptCore 执行js的解析,而 react native 运行在JavaScriptCore中,因此不存在浏览器兼容的问题。其结构如以下图:web
React Native实现的原理其实就是利用JS 调用Native 端的组件,并使用Native的组件来绘制界面,从而达到媲美原生应用的效果。apache
和前端开发不一样,React Native 所使用的标签并非真实的控件,React Native提供的组件会Dom 转换为Native的控件进行渲染。例如<Text>
标签会被转换为Android 中对应 TextView 控件。编程
须要说明的是,在React Native 中,JS端是运行在独立的线程中(称为JS Thread ),JS Thread 做为单线程逻辑,不可能处理耗时的操做。那么如 fetch 、图片加载 、 数据持久化等操做,在 Android 中实际对应的是 okhttp 、Fresco 、SharedPreferences等。而跨线程通讯,也意味着 Js Thread 和原生之间交互与通信是异步的。
由此能够看出,跨平台的关键在于C++层,开发人员大部分时候,只专一于JS 端的代码实现便可,无线了解底层的实现细节。 而若是要实现和原生模块的交互,只须要在原生端提供的各类 Native Module 模块(如网络请求,ViewGroup控件)便可,而后经过 JS 端提供的各类 JS Module(如JS EventEmiter模块)来实现调用。而且这些调用都会在C++实现的so中保存起来,双方的通信经过C++中的保存的映射,最终实现两端的交互,通讯的数据和指令,在中间层会被转为String字符串传输,双向的调用流程以下图。
在React Native混合项目中,JS代码会被打包成一个 bundle 文件,自动添加到 App 的资源目录下。react native 的打包脚本目录为/node_modules/react-native/local-cli,打包最后会经过 metro 模块压缩 bundle 文件。而bundle文件只会打包js代码,天然不会包含图片等静态资源,因此打包后的静态资源,实际上是被拷贝到对应的平台资源文件夹中。
举个例子,react native 项目会将图片存储在根目录下的 img/pic/logo.png 的资源,编译时,会被重命名后,根据大小 merged 到对应的是drawable目录下,修更名称为img_pic_logo.png。
Weex是阿里巴巴开源的一套移动跨平台开发框架,可以完美兼顾性能与动态性,让移动开发者经过简捷的前端语法写出Native级别的性能体验,并支持iOS、安卓、YunOS及Web等多端部署。目前,使用Weex框架的多半是阿里系的产品和一些创业的公司。
Weex的口号是“Write once, run everywhere”,Weex使用的耳熟能详的Vue,阿里的思惟是:写个 vue 前端,顺便完成一个apk 和 ipa,但其实仍是有差距的。Weex支持 web、android、ios 三端,原生端一样经过中间层转化,将控件和操做转化为原生逻辑来提升用户体验。。
在 Weex的架构层次中,主要包括三大部分:JS Bridge、Render、Dom,分别对应WXBridgeManager、WXRenderManager、WXDomManager,三部分经过WXSDKManager统一管理。其中 JS Bridge 和 Dom 都运行在独立的 HandlerThread 中,而 Render 运行在 UI 线程。关于Weex架构分层的内容读者能够自行查看官方资料的介绍。
其中,JS Bridge 主要用来和 JS 端实现进行双向通讯,好比把 JS 端的 dom 结构传递给 Dom 线程。Dom 主要是用于负责 dom 的解析、映射、添加等等的操做,最后通知UI线程更新。而 Render 负责在UI线程中对 dom 实现渲染。
和 React Native同样,Weex 全部的标签也不是真实控件,Weex的标签只不过是JS 代码中所生成存的 dom,最后都是由 Native 端解析,再获得对应的Native控件渲染。如 Android 中 <text>
标签对应 WXTextView 控件。
Weex 中文件默认为 .vue ,而 vue 文件是被没法直接运行的,因此 vue 会被编译成 .js 格式的文件,Weex SDK会负责加载渲染这个js文件。Weex能够作到跨三端的原理在于:在开发过程当中,代码模式、编译过程、模板组件、数据绑定、生命周期等上层语法是一致的。
不一样的是,在 JS Framework 层的最后,web 平台和 Native 平台,对 Virtual DOM 执行的解析方法是有区别的,在渲染真实 UI 的时候调用的接口也不一样的。
相比React Native,Weex主要是在JS V8的引擎上多了 JS Framework 承当了重要的职责,使得上层具有统一性,能够支持跨三个平台。总的来讲它主要负责是:管理Weex的生命周期,解析JS Bundle,转为Virtual DOM,再经过所在平台不一样的API方法,构建页面;进行双向的数据交互和响应。
在打包方案上,Weex和React Native都经过 Webpack 来打包bundle 文件的。不过,React Native打包若是不作拆分,打出的包是很大的,于是会本身制定一些拆包的规则。而Weex 做为React Native以后出现的跨平台实现方案,天然能够站在前人的肩膀上优化问题,好比:Bundle文件过大问题。 Weex 选择使用JS Framework 集成到 WeexSDK的方式,必定程度减小了JS Bundle的体积,使得 bundle 里面只保留业务代码。
打包时,weex 是经过 webpack 打包出 bundle 文件的。bundle 文件的打包和 entry.js 文件的配置数量有关,默认状况下以后一个 entry 文件,天然也就只有一个bundle文件。 在 weex 项目的 webpack.common.conf.js 中能够看到,其实打包也是区分了 webConfig 和 weexConfig 的不一样打包方式。
Flutter是Google用以帮助开发者在Ios和Android两个平台开发高质量原生应用的全新移动UI框架。与 React Native 和 Weex 框架使用的Javascript 技术不一样,Flutter 使用的是全新的编程语言Drat,因此执行时并不须要 Javascript 引擎,但实际效果最终也经过原生渲染。
Flutter框架主要分为 Framework 和 Engine两层,咱们基于Framework 开发App主要运行在 Engine 上。Engine 是 Flutter 的独立虚拟机,由它适配和提供跨平台支持,目前猜想 Flutter 应用程序在 Android 上,是直接运行 Engine 上 因此在是不须要Dalvik虚拟机。其架构图以下图所示:
得益于 Engine 层,Flutter 甚至不使用移动平台的原生控件, 而是使用本身 Engine 来绘制 Widget (Flutter的显示单元),而 Dart 代码都是经过 AOT 编译为平台的原生代码,因此 Flutter 能够 直接与平台通讯,不须要JS引擎的桥接。
而Flutter惟一要求系统提供的是canvas,用以实现UI的绘制。不过,Flutter 上 Android 自带了 Skia,Skia是一个 2D的绘图引擎库,跨平台,因此能够被嵌入到 Flutter的 iOS SDK中,也使得 Flutter Android SDK要比 iOS SDK小不少。
下面对上面介绍的几大框架进行一个简单的对比,以方便读者进行对比学习。
对比类型 | React Native | Weex | Flutter |
---|---|---|---|
实现技术 | JavaScript | JavaScript | 原生编码,无桥接 |
引擎 | JS V8 | JSCore | Flutter engine |
使用语言 | React | Vue | Dart |
bundle文件大小 | 默认单1、较大 | 较小、多页面可多文件 | 不须要 |
上手难度 | 稍高大 | 容易 | 简单 |
框架难度 | 较重 | 较轻 | 重 |
支持对象 | Android、IOS | Android、IOS、Web | Android、IOS |
上面Apk大小是经过 react-native init、weex create 和 flutter 建立出的工程后,直接不添加任何代码,打包出来的 release 签名 apk 大小。从下图能够看出,其中大比例都是在so库。