移动端跨平台方案对比:React Native、weex、Flutter

跨平台一直是老生常谈的话题,cordova、ionic、react-native、weex、kotlin-native、flutter等跨平台框架百花齐放,很有一股推倒原生开发者的势头。javascript

为何咱们须要跨平台开发? 本质上,跨平台开发是为了增长代码复用,减小开发者对多个平台适配的工做量,下降开发成本,提升业务专一的同时,提供比web更好的体验。html

目前移动端跨平台开发中,备受关注的方案大体概括为如下几种状况:前端

  • 1)react native、weex均使用JavaScript做为编程语言,目前JavaScript在跨平台开发中,可谓占据半壁江山,大有“一统天下”的趋势;
  • 2)kotlin-native开始支持 iOS 和 Web 开发,(kotlin已经成为android的一级语言)也想尝试“一统天下”;
  • 3)flutter是Google跨平台移动UI框架,Dart做为谷歌的亲儿子,毫无疑问Dart成为flutter的编程语言。做为巨头新生儿,在flutter官网也能够看出,flutter一样“心怀天下”(可支持Web端、Android端、iOS端等)。

 

本篇主要以react-native、weex、flutter,深刻聊聊当前最火的这3种跨平台移动开发方案的实现原理、现状与将来。至于为何只讲它们,由于对比ionic、phoneGap,它们更于 “naive” (˶ ⁻̫ ˵)。看完本篇,相信你会对于当下跨平台移动开发的现状、实现原理、框架的选择等有更深刻的理解。vue

一、React Native的原理与特性介绍java

React Native技术关键词:node

  • 1)Facebook 出品;
  • 2)JavaScript语言;
  • 3)JSCore引擎;
  • 4)React设计模式;
  • 5)原生渲染。

 

1.1理念架构react

“Learn once, write anywhere” ,表明着 Facebook对 react native 的定义:学习 react ,同时掌握 web 与 app 两种开发技能。 react native 用了 react 的设计模式,但UI渲染、动画效果、网络请求等均由原生端实现。开发者编写的js代码,经过 react native 的中间层转化为原生控件和操做,比ionic等跨平台应用,大大提升了的用户体验。android

总结起来其实就是:React Native是利用 JS 来调用 Native 端的组件,从而实现相应的功能。webpack

 

react native 的跨平台实现主要由三层构成,其中 C++ 实现的动态连结库(.so),做为中间适配层桥接,实现了js端与原生端的双向通讯交互。这里最主要是封装了 JavaScriptCore 执行js的解析,而 react native 运行在JavaScriptCore中,因此不存在浏览器兼容的问题。ios

其中在IOS上直接使用内置的javascriptcore, 在Android 则使用webkit.org官方开源的jsc.so。

 

1.二、实现原理

 和前端开发不一样,react native 全部的标签都不是真实控件,JS代码中所写控件的做用,相似 Map 中的 key 值。JS端经过这个 key 组合的 Dom ,最后Native端会解析这个 Dom ,获得对应的Native控件渲染,如 Android 中<view> 标签对应 ViewGroup 控件。

 在 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字符串传输,

 

1.三、打包加载

 最终,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。

 打包Android和IOS,确定须要相应的平台项目存在,在 react-native init 时建立的项目,就已经包含了 android 和 ios 的模版工程,打包完的工程会加载bundle文件,而后启动项目

二、WEEX

Alibaba 出品,JavaScript语言,JS V8引擎,Vue设计模式,原生渲染

2.一、理念架构

 “Write once, run everywhere”, weex的定义就像是:写个 vue 前端,顺便帮你编译成性能还不错的 apk 和 ipa(固然,现实有时很骨感)。基于 Vue 设计模式,支持 web、android、ios 三端,原生端一样经过中间层转化,将控件和操做转化为原生逻辑来提升用户体验。

 在 weex 中,主要包括三大部分:JS Bridge、Render、Dom,分别对应WXBridgeManager、WXRenderManager、WXDomManager,三部分经过WXSDKManager统一管理。其中 JS Bridge 和 Dom 都运行在独立的 HandlerThread 中,而 Render 运行在 UI 线程。

 JS Bridge 主要用来和 JS 端实现进行双向通讯,好比把 JS 端的 dom 结构传递给 Dom 线程。Dom 主要是用于负责 dom 的解析、映射、添加等等的操做,最后通知UI线程更新。而 Render 负责在UI线程中对 dom 实现渲染。

 

2.二、实现原理

 和 react native同样,weex 全部的标签也不是真实控件,JS 代码中所生成存的 dom,最后都是由 Native 端解析,再获得对应的Native控件渲染,如 Android 中 <text> 标签对应 WXTextView 控件。

 weex 中文件默认为 .vue ,而 vue 文件是被没法直接运行的,因此 vue 会被编译成 .js 格式的文件,Weex SDK会负责加载渲染这个js文件。Weex能够作到跨三端的原理在于:在开发过程当中,代码模式、编译过程、模板组件、数据绑定、生命周期等上层语法是一致的。不一样的是在 JS Framework 层的最后,web 平台和 Native 平台,对 Virtual DOM 执行的解析方法是有区别的。

 实际上,在 Native 中对 bundle 文件的加载大体经历如下阶段:

  • weex 接收到 js 文件之后,JS Framework 根据文件为 Vue 模式,会调用weex-vue-framework 中提供的 createInstance方法建立实例。(也多是Rax模式)
  • createInstance 中会执行 Js Entry 代码里 new Vue() 建立一个组件,经过其 render 函数建立出 Virtual DOM 节点。
  • 由JS V8 引擎上解析 Virtual DOM ,获得 Json 数据发送至 Dom 线,这里输出 Json 也是方便跨端的数据传输。
  • Dom 线程解析 Json 数据,获得对应的 WxDomObject,而后建立对应的WxComponent 提交 Render 。
  • Render在原生端最终处理处理渲染任务,并回调里JS方法。

 得益于上层的统一性,只是经过 weex-vue-framework 判断是由Vue.js 生成真实的 Dom ,仍是经过 Native Api 渲染组件,weex 必定程度上上,用JS 实现了 vue 一统天下的效果。

  weex 在原生渲染 Render 时,在接收到渲染指令后,会逐步将数据渲染成原生组件。Render 经过解析渲染数据的描述,而后分发给不一样的模块。

  好比 控件渲染属于 dom 模块中,页面跳转属于navigator模块等。模块的渲染过程并不是一个执行完,再执行另外一个的流程,而是相似流式的过程。如上一个 <text> 的组件还没渲染好,下一个 <div> 的渲染又发了过来。这样当一个组件的嵌套组件不少时,或者能够看到这个大组件内的UI,一个一个渲染出来的过程。

 weex 比起react native,主要是在JS V8的引擎上,多了 JS Framework 承当了重要的职责,使得上层具有统一性,能够支持跨三个平台。总的来讲它主要负责是:管理Weex的生命周期;解析JS Bundle,转为Virtual DOM,再经过所在平台不一样的API方法,构建页面;进行双向的数据交互和响应。

 

2.三、打包

 weex 做为 react-native 以后出现的跨平台实现方案,天然能够站在前人的肩膀上优化问题,好比:Bundle文件过大问题。

 Bundle文件的大小,很大程度上影响了框架的性能,而 weex 选择将 JS Framework 集成到 WeexSDK 中,必定程度减小了JS Bundle的体积,使得 bundle 里面只保留业务代码。

 打包时,weex 是经过 webpack 打包出 bundle 文件的。bundle 文件的打包和 entry.js 文件的配置数量有关,默认状况下以后一个 entry 文件,天然也就只有一个bundle文件。

 在 weex 项目的 webpack.common.conf.js 中能够看到,其实打包也是区分了 webConfig 和 weexConfig 的不一样打包方式。以下图,其中weexEntry 就是 weex 打包配置的地方,能够看到原本已经有 index 和 entry.js 存在了。若是有须要,可配置上你须要的打包页面,具体这里就不详细展开了。有兴趣可看:Weex原理之带你去蹲坑 。

 

三、Flutter

Google 出品,Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

 Flutter 是谷歌2018年发布的跨平台移动UI框架。相较于本人已经在项目中使用过 react native 和 Weex,Flutter目前仅仅是简单运行过Demo,毕竟仍是beta 阶段,这里更多的聊一下它的实现机制和效果。

 与 react native 和 weex 的经过 Javascript 开发不一样,Flutter 的编程语言是Drat,(谷歌亲儿子,听说是由于 Drat 项目组就在 Flutter 隔壁而被选上(◐‿◑))因此执行时并不须要 Javascript 引擎,但实际效果最终也经过原生渲染。

 Flutter 主要分为 Framework 和 Engine,咱们基于Framework 开发App,运行在 Engine 上。Engine 是 Flutter 的独立虚拟机,由它适配和提供跨平台支持,目前猜想 Flutter 应用程序在 Android 上,是直接运行 Engine 上 因此在是不须要Dalvik虚拟机。(这是比kotlin更完全,抛弃JVM的纠缠?)

 得益于 Engine 层,Flutter 甚至不使用移动平台的原生控件, 而是使用本身 Engine 来绘制 Widget (Flutter的显示单元),而 Dart 代码都是经过 AOT 编译为平台的原生代码,因此 Flutter 能够 直接与平台通讯,不须要JS引擎的桥接。同时 Flutter 惟一要求系统提供的是 canvas,以实现UI的绘制。咦?这么想来,支持web端也没问题吧!

 在Flutter中,大多数东西都是widget,而widget是不可变的,仅支持一帧,而且在每一帧上不会直接更新,要更新而必须使用Widget的状态。无状态和有状态 widget 的核心特性是相同的,每一帧它们都会从新构建,有一个State对象,它能够跨帧存储状态数据并恢复它。

 Flutter 上 Android 自带了 Skia,Skia是一个 2D的绘图引擎库,跨平台,因此能够被嵌入到 Flutter的 iOS SDK中,也使得 Flutter Android SDK要比 iOS SDK小不少。

3、对比

 这算是互相伤害的环节了吧。(///▽///)

类型

React Native

Weex

Flutter

平台实现

JavaScript

JavaScript

无桥接,原生编码

引擎

JS V8

JSCore

Flutter engine

核心语言

React

Vue

Dart

Apk大小 (Release)

7.6M

10.6M

8.1M

bundle文件大小

默认单1、较大

较小、多页面可多文件

不须要

上手难度

稍高?

容易

通常

框架程度

较重

较轻

特色(不局限)

适合开发总体App

适合单页面

适合开发总体App

社区

丰富,Facebook重点维护

有点残念,托管apache

刚刚出道小鲜肉,拥护者众多

支持

Android、IOS

Android、IOS、Web

Android、IOS(并不止?)

一、大小

 上面Apk大小是经过 react-native init、weex create 和 flutter 建立出的工程后,直接不添加任何代码,打包出来的 release 签名 apk 大小。从下图能够看出,其中大比例都是在so库。

 

二、社群

 react native 做为 Facebook 主力开源项目之一,至今已有各种丰富的第三方库,甚至如 realm、lottie 等开源项目也有 react native 相关的版本,社群实际无需质疑。固然,由于并彻底正统开发平台,第三库的健壮性和兼容性有时候老是参差不齐。

 weex 其实有种生错在国内的感受。其实 weex 的设计和理念都很优秀,性能也不错,可是对比 react native 的第三方支持,就显得有点后妈养的。2016年开源至今,社区和各种文档都显得有点疲弱,做为跨平台开发人员,大多时候确定不会但愿,须要频繁的本身增长原生功能支持,由于这样的工做一多,反而会与跨平台开发的理念背道而驰,带来开发成本被维护难度增长。

 Flutter目前还处理beta阶段,可是谷歌的号召力一直很可观,这一点无需质疑。

三、性能

 理论上 flutter 的性能应该是最好的,可是目前实际体验中,却并无感觉出来太大的差距,和 react native(0.5.0以后)、weex 在性能上我的体验差别不是很大。固然,这里并无实测渲染的毫秒时间和帧率数据。

四、其余区别

  • Weex的多页面实现问题

 weex 在 native 端是不支持 <keep-alive> 的,这一点和 react-native 不一样在与,若是在 native 须要实现页面跳转,使用 vue-router 将会惨不忍睹:返回后页面不作特别处理时,是会空白一片。参考官方Demo playground,native 端 的采用 weex.requireModule('navigator') 跳转 Activity 是才正确实现。

 同时,weex中 navigator 跳转的设计,也致使了多页面的页面间通信的差别。weex在多页面下的数据通信,是经过url实现的,好比file://assets/dist/SecondPage.js?params=0,而vuex和vue-router在跨页面是没法共用的;而 react native 在跨 Actvity 使用时,由于是同一个bundle文件,只要 manager 相同,那么 router 和 store 时能够照样使用的,数据通讯方式也和当个 Actvity 没区别。

  • 项目模板

  weex 和 react native 模板代码模式也不一样。weex 的模板是从 cordova 模式修改过来的,根据platform需求,用命令添加固定模块,而在 .gitignore 对 platforms 文件夹是忽略跟踪。 react native 在项目建立时模版就存在了,特别是添加第三方插件原生端支持时,会直接修改模板代码,git代码中也会添加跟踪修改。

4、将来趋势

  咱们选择框架的时候,不少时候会关注框架的成熟度和生命力不是么(◐‿◑)。

一、React Native

  “Airbnb 宣布放弃使用 React Native,回归使用原生技术” : Airbnb 做为 react native 平台上最大的支持者之一,其开源的lottie 一样是支持原生和 react native。

 Airbnb 在宣布放弃的文中,也对 react native 的表示了很大量的确定,而使得他们放弃的理由,其实主要仍是集中于项目庞大以后的维护困难,第三方库的参差不齐,兼容上须要耗费更多的精力致使放弃。

ps:( Lottie库Airbnb出的是一个可以帮助解析AE导出的包含动画信息的json文件。这很好的解决了一个矛盾,设计师能够更专一的设计出各类炫酷的动画效果,而开发只须要将其加入支持便可。)

  Facebook 正在重构 React Native,将重写大量底层。在经历了开源协议风波后,能够看出 Facebook 对于 react native 仍是很看重的, 这些底层重构优化的地方,主要集中于:

 首先,改变线程模型。UI 更新再也不须要在三个不一样的线程上执行,而是能够在任意线程上同步调用 JavaScript 进行优先更新,同时将低优先级工做推出主线程,以便保持对 UI 的响应。

 其次,将异步渲染功能引入 React Native 中,容许执行多个渲染并简化异步数据处理。

 最后,简化桥接,让它更快、更轻量。原生和 JavaScript 之间的直接调用效率更高,而且能够更轻松地构建调试工具,如跨语言堆栈跟踪。

二、Weex

  没有死!阿里公开Weex技术架构,还开源了一大波组件。 2018年初的新闻能够看出,weex 的遭遇有点相似曾经的 Duddo(Dubbo由于内部竞争被阿里一度放弃维护),这波诈尸后 weex 被托管到了Apache,而github的 weexteam 现在也还保持着更新,但愿后续能有多好的发展,拭目以待吧。

三、Flutter

 Flutter 是 Google 跨平台移动UI框架,Dart做为谷歌的亲儿子在 Flutter 中使用,而且谷歌新操做系统 Fuchsia 支持 Dart,使用 Flutter 做为操做UI框架。这些集合到一块儿不免让你怀疑 Android 是否要被谷歌抛弃的想法。

 或者现在先 Android 等平台上推广 Flutter 与 Dart,就是为了之后跟好的过渡到新系统上,毕竟开发者是操做系统的生命源泉之一。而 Java 与 JVM 或者能够被谷歌彻底抛开。固然,目前看起来 Flutter 貌似还缺乏一些语法糖,嵌套下来的代码有点不忍直视,或者到正式版以后,咱们更能感觉出它的美丽吧。

相关文章
相关标签/搜索