默认
打赏 发表评论 4
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
最火移动端跨平台方案盘点:React Native、weex、Flutter
阅读(101501) | 评论(4 收藏3 淘帖1 2
微信扫一扫关注!

1、前言


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

为什么我们需要跨平台开发? 本质上,跨平台开发是为了增加代码复用,减少开发者对多个平台差异适配的工作量,降低开发成本,提高业务专注的同时,提供比web更好的体验。嗯~通俗了说就是:省钱、偷懒。

目前移动端跨平台开发中,备受关注的方案大致归纳为以下几种情况:

  • 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” (˶ ⁻̫ ˵)。看完本篇,相信你会对于当下跨平台移动开发的现状、实现原理、框架的选择等有更深入的理解。

相关文章:推荐您同时阅读本站的另两篇同类文章《盘点主流移动端跨平台UI技术:实现原理、技术优劣、横向对比等》、《小程序技术始于微信?来看看移动端小程序技术的前世今生!》。

最火移动端跨平台方案盘点:React Native、weex、Flutter_1.jpg

2、React Native的原理与特性介绍


React Native技术关键词:

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

2.1理念架构


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

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

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

最火移动端跨平台方案盘点:React Native、weex、Flutter_2.jpg

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

2.2实现原理


和前端开发不同:react native 所有的标签都不是真实控件,JS代码中所写控件的作用,类似 Map 中的 key 值。JS端通过这个 key 组合的 Dom ,最后Native端会解析这个 Dom ,得到对应的Native控件渲染,如 Android 中<view> 标签对应 ViewGroup 控件。

最火移动端跨平台方案盘点:React Native、weex、Flutter_3.png

在 react native 中,JS端是运行在独立的线程中(称为JS Thread )。JS Thread 作为单线程逻辑,不可能处理耗时的操作。那么如 fetch 、图片加载 、 数据持久化 等操作,在 Android 中实际对应的是 okhttp 、Fresco 、SharedPreferences等。而跨线程通信,也意味着 Js Thread 和原生之间交互与通讯是异步的。

可以看出,react native 跨平台的关键在于C++层,开发人员大部分时候,只专注于JS 端的代码实现。 在原生端提供的各种 Native Module 模块(如网络请求,ViewGroup控件),和 JS 端提供的各种 JS Module(如JS EventEmiter模块),都会在C++实现的so中保存起来,双方的通讯通过C++中的保存的映射,最终实现两端的交互。通信的数据和指令,在中间层会被转为String字符串传输,双向的调用流程如下图。

最火移动端跨平台方案盘点:React Native、weex、Flutter_4.png

最火移动端跨平台方案盘点:React Native、weex、Flutter_5.png

2.3打包加载


最终: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文件,然后启动项目,如下图。这里就不展开了,有兴趣的可以看QQ空间移动开发团队分享的《React Native For Android 架构初探》。

最火移动端跨平台方案盘点:React Native、weex、Flutter_6.jpg
▲ react native完成启动流程图(图片来源于QQ空间移动开发团队)

3、WEEX的原理与特性介绍


WEEX技术关键词:

  • 1)Alibaba 出品;
  • 2)JavaScript语言;
  • 3)JS V8引擎;
  • 4)Vue设计模式;
  • 5)原生渲染。

3.1理念架构


“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 实现渲染。

最火移动端跨平台方案盘点:React Native、weex、Flutter_1.jpg

3.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 执行的解析方法是有区别的

最火移动端跨平台方案盘点:React Native、weex、Flutter_2.png

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

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

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

最火移动端跨平台方案盘点:React Native、weex、Flutter_3.jpg

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

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

weex 比起react native,主要是在JS V8的引擎上,多了 JS Framework 承当了重要的职责,使得上层具备统一性,可以支持跨三个平台

总的来说JS Framework主要负责的是:

  • 1)管理Weex的生命周期;
  • 2)解析JS Bundle,转为Virtual DOM,再通过所在平台不同的API方法构建页面;
  • 3)进行双向的数据交互和响应。

最火移动端跨平台方案盘点:React Native、weex、Flutter_4.jpg

3.3打包


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原理之带你去蹲坑》。

最火移动端跨平台方案盘点:React Native、weex、Flutter_5.png

4、Flutter的原理与特性介绍


Flutter技术关键词:

  • 1)Google 出品;
  • 2)Dart语言;
  • 3)Flutter Engine引擎;
  • 4)响应式设计模式;
  • 5)原生渲染。

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

与 react native 和 weex 的通过 Javascript 开发不同,Flutter 的编程语言是Drat,所以执行时并不需要 Javascript 引擎,但实际效果最终也通过原生渲染

最火移动端跨平台方案盘点:React Native、weex、Flutter_1.png

如上图,Flutter 主要分为 Framework 和 Engine,我们基于Framework 开发App,运行在 Engine 上。Engine 是 Flutter 的独立虚拟机,由它适配和提供跨平台支持,目前猜测 Flutter 应用程序在 Android 上,是直接运行 Engine 上 所以在是不需要Dalvik虚拟机(这是比kotlin更彻底,抛弃JVM的纠缠?

如下图,得益于 Engine 层,Flutter 甚至不使用移动平台的原生控件, 而是使用自己 Engine 来绘制 WidgetFlutter的显示单元),而 Dart 代码都是通过 AOT 编译为平台的原生代码,所以 Flutter 可以 直接与平台通信,不需要JS引擎的桥接。同时 Flutter 唯一要求系统提供的是 canvas,以实现UI的绘制。咦?这么想来,支持web端也没问题吧!

最火移动端跨平台方案盘点:React Native、weex、Flutter_2.jpg

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

Flutter 上 Android 自带了 Skia,Skia是一个 2D的绘图引擎库,跨平台,所以可以被嵌入到 Flutter的 iOS SDK中,也使得 Flutter Android SDK要比 iOS SDK小很多。

热门话题:为什么Flutter会选择 Dart作为开发语言?

八卦消息认为:“是因为 Drat 项目组就在 Flutter 隔壁而被选上”。

实际上真实的原因是:早期的Flutter团队评估了十多种语言,并选择了Dart,因为它符合他们构建用户界面的方式。

Dart之所以成为Flutter不可或缺的一部分,根本原因还是因为其具有以下特性:

  • 1)Dart是AOT(Ahead Of Time)编译的,编译成快速、可预测的本地代码,使Flutter几乎都可以使用Dart编写。这不仅使Flutter变得更快,而且几乎所有的东西(包括所有的小部件)都可以定制;
  • 2)Dart也可以JIT(Just In Time)编译,开发周期异常快,工作流颠覆常规(包括Flutter流行的亚秒级有状态热重载);
  • 3)Dart可以更轻松地创建以60fps运行的流畅动画和转场。Dart可以在没有锁的情况下进行对象分配和垃圾回收。就像JavaScript一样,Dart避免了抢占式调度和共享内存(因而也不需要锁)。由于Flutter应用程序被编译为本地代码,因此它们不需要在领域之间建立缓慢的桥梁(例如,JavaScript到本地代码)。它的启动速度也快得多;
  • 4)Dart使Flutter不需要单独的声明式布局语言,如JSX或XML,或单独的可视化界面构建器,因为Dart的声明式编程布局易于阅读和可视化。所有的布局使用一种语言,聚集在一处,Flutter很容易提供高级工具,使布局更简单;
  • 5)开发人员发现Dart特别容易学习,因为它具有静态和动态语言用户都熟悉的特性。

并非所有这些功能都是Dart独有的,但它们的组合却恰到好处,使Dart在实现Flutter方面独一无二。因此,没有Dart,很难想象Flutter像现在这样强大。

有关此话题的详细文章请见《为什么Flutter会选择 Dart ?》。

5、React Native、weex、Flutter 3种方案横向对比


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

最火移动端跨平台方案盘点:React Native、weex、Flutter_WX20180812-220822@2x.jpg

5.1最终程序大小


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

最火移动端跨平台方案盘点:React Native、weex、Flutter_2.png

5.2社群支持


react native 作为 Facebook 主力开源项目之一,至今已有各类丰富的第三方库,甚至如 realm、lottie 等开源项目也有 react native 相关的版本,社群实际无需质疑。当然,因为并完全正统开发平台,第三库的健壮性和兼容性有时候总是良莠不齐。

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

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

5.3性能区别


理论上 flutter 的性能应该是最好的,但是目前实际体验中,却并没有感受出来太大的差距,和 react native(0.5.0之后)、weex 在性能上个人体验差异不是很大。当然,这里并没有实测渲染的毫秒时间和帧率数据。

5.4其他区别


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代码中也会添加跟踪修改。

6、未来趋势展望


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

6.1React Native


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

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

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

Facebook 正在重构 React Native,将重写大量底层。在经历了开源协议风波后,可以看出 Facebook 对于 react native 还是很看重的。

这些底层重构优化的地方,主要集中于:

  • 1)首先:改变线程模型。UI 更新不再需要在三个不同的线程上执行,而是可以在任意线程上同步调用 JavaScript 进行优先更新,同时将低优先级工作推出主线程,以便保持对 UI 的响应;
  • 2)其次:将异步渲染功能引入 React Native 中,允许执行多个渲染并简化异步数据处理;
  • 3)最后:简化桥接,让它更快、更轻量。原生和 JavaScript 之间的直接调用效率更高,并且可以更轻松地构建调试工具,如跨语言堆栈跟踪。


其他React Native相关文章:


6.2Weex


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

6.3Flutter


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

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

(原文链接:https://www.jianshu.com/p/7e0bd4708ba7,内容有改动)

附录:更多移动端开发精华文章


全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等
美图App的移动端DNS优化实践:HTTPS请求耗时减小近半
金蝶随手记团队分享:还在用JSON? Protobuf让数据传输更省更快(原理篇)
金蝶随手记团队分享:还在用JSON? Protobuf让数据传输更省更快(实战篇)
腾讯技术分享:社交网络图片的带宽压缩技术演进之路
通俗易懂:基于集群的移动端IM接入层负载均衡方案分享
QQ音乐团队分享:Android中的图片压缩技术详解(上篇)
QQ音乐团队分享:Android中的图片压缩技术详解(下篇)
腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率
腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)
腾讯原创分享(三):如何大幅压缩移动网络下APP的流量消耗(下篇)
基于社交网络的Yelp是如何实现海量用户图片的无损压缩的?
腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(图片压缩篇)
腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(音视频技术篇)
最火移动端跨平台方案盘点:React Native、weex、Flutter
盘点主流移动端跨平台UI技术:实现原理、技术优劣、横向对比等
iPhone X 的 UI界面适配官方指南!》
《[url=http://www.52im.net/thread-1843-1-1.html]新浪微博技术分享:微博短视频服务的优化实践之路

全面掌握移动端主流图片格式的特点、性能、调优等
迈向高阶:优秀Android程序员必知必会的网络基础
HTTPS时代已来,打算更新你的HTTP服务了吗?
移动端APP的日志上报机制的优化实践
移动端网络优化之HTTP请求的DNS优化
伪即时通讯:分享滴滴出行iOS客户端的演进过程
Android版微信从300KB到30MB的技术演进(PPT讲稿) [附件下载]
微信团队原创分享:Android版微信从300KB到30MB的技术演进
Android程序员的痛你永远不懂(一):Bitmap到底占用多大内存?
Android程序员的痛你永远不懂(二):如何减少Bitmap内存占用?
Android反编译利器APKDB:没有美工的日子里继续坚强的撸
微信团队原创分享:Android内存泄漏监控和优化技巧总结
全面总结iOS版微信升级iOS9遇到的各种“坑”
微信团队原创资源混淆工具:让你的APK立减1M
微信团队原创Android资源混淆工具:AndResGuard [有源码]
Android版微信安装包“减肥”实战记录
iOS版微信安装包“减肥”实战记录
移动端IM实践:iOS版微信界面卡顿监测方案
iOS端移动网络调优的8条建议
微信“红包照片”背后的技术难题
移动端IM实践:iOS版微信小视频功能技术方案实录
移动端IM实践:Android版微信如何大幅提升交互性能(一)
移动端IM实践:Android版微信如何大幅提升交互性能(二)
移动端IM实践:iOS版微信的多设备字体适配方案探讨
爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结
>> 更多同类文章 ……

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

上一篇:调皮的程序员:Linux之父雕刻在Linux内核中的故事下一篇:迷茫中前行:一个专科渣渣菜鸟的编程入门感悟

本帖已收录至以下技术专辑

推荐方案
评论 4
~学习,学习, ,有空看看
签名: Com on
rainbowchat用的什么框架?
引用:coolan2013 发表于 2019-06-16 17:50
rainbowchat用的什么框架?

原生代码。im这种对体验很敏感的高频应用,不适合用这些乱七八糟开发效率至上的混合框架
引用:JackJiang 发表于 2019-06-16 20:33
原生代码。im这种对体验很敏感的高频应用,不适合用这些乱七八糟开发效率至上的混合框架

谢谢回复!
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部