38

Flutter、React Native、Uni-app比较,到底哪个值得投入?

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzI0MDIwNTQ1Mg%3D%3D&%3Bmid=2676493231&%3Bidx=1&%3Bsn=825515727d27b3a162a68f52d22547ae
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

RnQrIvq.jpg!web

前言

每当我们评估新技术时要问的第一个问题就是“它会给我们的业务和客户带来哪些价值?”,工程师们很容易对闪闪发光的新事物着迷,却经常会忽略这些新事物其实可能对我们的客户没有任何好处,反而只会让现有的工作流程更加复杂。

Flutter最近比较热闹,毕竟是Google出品。

但我们不是炒作热点的媒体,也不是忽悠你交学费的培训机构,我们作为实际的跨平台开发者,冷静的分析下这个东东。

Flutter是Google为Fuchsia操作系统设计的应用开发方式。

iaiUjyz.jpg!web

Fuchsia OS 要兼容廉价物联网设备,要求对硬件的消耗降低,并且为了避免与 Oracle 的Java打官司,Fuchsia 使用了 Dart 语言+flutter界面库的方式。

从设计上来看,这套方案的性能确实够高。 Dart 虽然属于大前端范畴,但Dart是和Java一样的强类型语言,这让Dart虚拟机可以做很多优化,性能方面超出了js。

Dart曾经与 Typescript 竞争,谁才是更好的js?但不幸输给了Typescript,Chrome也放弃了内置Dart虚拟机的计划。

不过Dart团队没有解散,几年后,他们借助Flutter,再次出现在公众面前。

7Vfi2y7.png!web

性能分析和写法的对比

Flutter作为界面库(注意它只是界面库,Dart语言是另一个项目),它唯一要干的事情就是渲染界面。不像HTML5,Flutter界面库连视频、定位等都没有,就是一个纯排版引擎,绘制文字、按钮、图片等常用界面控件。

这个排版引擎的特点是简单、高性能。

在3大主流渲染引擎里,webview、react native/weex、flutter,复杂度依次降低,渲染性能依次上升。( uni-app 是双渲染引擎,webview和weex都内置了,随便开发者使用切换)

所以我们要清楚,提升性能是有代价的,你究竟想要灵活丰富的CSS3,还是想要固定flex模式排版,抑或是最简单但高性能的Flutter排版?开发便利性和运行性能不可兼得。

同时我们要明白,性能的差别,并不是因为Google的Chrome团队、Android团队的技术比同公司的Flutter团队差。而是Flutter提供的布局写法是被限制过的,解析快,所以渲染快。别忘了webview的排版引擎也是世界级工程师用c写的。

但通过这种方式提升性能的代价,就是布局复杂的界面时,Flutter的代码嵌套的让人崩溃。

我们先举个例子,同样的界面,用HTML和Flutter如何实现。

HTML实现:

<div class="greybox">
    <div class=redbox>
        smaple text
    </div>
</div>
<style>
.greybox {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 18px
}
.redbox {
    background-color: #ef5350; /* red 400 */
    padding: 16px;
    color: #ffffff
    }
</style>

Flutter如何实现:

var container = new Container( // grey box
  child: new Center(
    child: new Container( // red box
      child: new Text(
        "smaple text",
        style: new TextStyle(
          color: Colors.white,
          fontSize: 18.0,
        ),
      ),
      decoration: new BoxDecoration(
        color: Colors.red[400],
      ),
      padding: new EdgeInsets.all(16.0),
    ),
  ),
  width: 320.0,
  height: 240.0,
  color: Colors.grey[300],
);

可以看出,从代码的写法来说,Flutter没有tag和样式的说法,更没有选择器,从头到尾只有Dart语言,它的界面控件是用Dart代码 new 出来的,每个控件的样式,是在 new 的时候设置的json参数。 如果我们要嵌套布局,就要不停的在Dart里写child,同时在Dart里给child们设样式参数。上面的代码,只是嵌套了1层,实际开发中,DOM要嵌套好多层,想象那样的代码。。。所以大家都诟病Dart是“嵌套地狱”。

或者,你可以这么理解,这是一个只有js 没有html和css的浏览器。你需要用js createElement 来创建元素,用js的 style 方法给每个element设 style ,反正就是不能写html和css代码。前端都已经发展到各种mvc等视图逻辑分离的架构了,也有了Vue组件这种组件化模式方便用各种轮子快速完成界面。你是否能适应Dart这种低效的界面开发模式?从开发模式来讲,这确实是一种倒退。

浏览器的HTML提供了tag和样式分离的写法,还有各种各样的选择器,但其实这也是有代价的。它导致Webview初始化时要同时先启动Webkit排版引擎来解析这些编写随性的HTML、CSS,同时还要启动一个JS引擎比如V8或JSCore来解析里面的JS。

而Dart就很简单,只启动一个Dart引擎,解析严格的Dart语法,它不会去操心有些标签未闭合要如何容错,不会判断宽度320后面是 px 还是 rem 或者是动态计算百分比。

对比这2个引擎初始化时要干的事,差别简直太大了。

所以从解析效率上,Flutter肯定比Webview要高。但从编码灵活性上,Flutter写的代码,嗯,难看而低效!

Flutter使用的也是Flex布局思想,这是一个强嵌套布局模型,比Web常规排版引擎的嵌套更多。当界面复杂时 Flutter 的代码要嵌套几十层,每层的元素的json样式都和元素一起混写在Dart代码里,让人崩溃。

有人提出是否可以通过一种预编译的DSL来简化写法,让Flutter的开发不这么痛苦。

但这个难度太大了,从严格转换为松散是简单的,从松散转换为严格几乎是不可能的。

什么意思呢?比如Flutter代码转换Web代码,是很简单的,Flutter已经自带了这个功能。但是想反过来,那可难了。

类似的还有,把Typescript转为JS是容易的,反之,不是绝对不可行,但会复杂到你宁愿去重写一套Typescript代码。

Flutter的性能高,除了简单严格,还有一个特点,就是逻辑层与视图层统一,运行在同一套Dart虚拟机下。

我们知道RN和Weex,也是原生渲染的,它们的性能高于Webview。但同为原生渲染的,怎么会慢于Flutter呢?其实不是原生渲染慢,而是JS和原生通信慢。

RrQvQ3f.jpg!web

RN和Weex都采用了独立的JS引擎(iOS是JSCore,Android是V8,最新版RN开始在Android上搞自己的JS引擎),从JS与Dart的比较上,性能稍逊一筹。但这不是主要问题,主要问题是,RN、Weex的JS引擎和原生渲染层是两个运行环境。

当JS引擎联网获取到数据后,通知原生视图层更新界面时,有一个跨环境的通信折损。同样,当用户在屏幕上操作原生视图层时,要给JS引擎发送通知,也会产生这个通信折损。

不过这种性能差别,在大多数场景中,用户是感受不到的。比较影响的场景,是跟手式的JS响应操作绘制帧动画。

这方面,Weex有个值得称赞的技术是 BindingX ,它可以预定义规则,让用户界面在原生层交互时通过预定义规则直接响应,而无需传递给JS层。在需要短时间内来回通信的场景时,可以使用BindingX这类解决方案。它的性能和灵活性比RN更强了一些。

说回来Flutter,它只有一个Dart引擎,没有来回通信产生的性能问题。不过任何事情都是有利有弊的, Flutter在普通的界面绘制上效率虽然高,但一旦涉及原生的界面,反而会遇到更多问题。

前面已经说过,Flutter只是一个基础排版引擎,缺少很多能力,当我们需要在Flutter界面上内嵌一个原生的视频播放扩展控件时(Flutter没有视频播放能力),或者原生的高德地图SDK,那么在拖动视频进度时、拖动地图时,Flutter一样会产生原生和Dart之间的通信,造成性能损耗。

事实上,由于Flutter是在一个类Canvas环境绘制的,想把一个原生控件嵌入Flutter的布局里某些元素之间去排版,还不是一件容易做到的事情,坑很多。

每个人都想要一个像CSS3那样灵活写法的布局引擎,他们给React Native和Weex提需求,给Flutter提需求。殊不知,让这些产品团队实现了CSS3时,他们的性能优势已经不再了,他们相当于又实现了一遍Webview。这种无意义的需求,他们是不会受理了。

性能好,有个度,客观地讲,RN/Weex调用原生渲染的性能,和Flutter的渲染性能,在用户体验上并没有明显区别,甚至在很多场景下,和Webview渲染的小程序也没有明显区别。

也简单说说Webview渲染小程序,为什么性能高,核心是预载。点击一个新页面时,Webview是提前创建好的,不会走复杂的Webkit、V8的初始化流程,连开发者的JS代码,也是预载好的。所以点击新页面时,它的渲染速度和原生应用没什么差别。当然也有个坏处,就是启动慢。微信里启动小程序速度看着还行,其实是微信在启动小程序之前,就已经提前初始化了小程序运行环境。

即便是排版引擎,UI库好用吗?

不管是RN还是Flutter,有一个设计很不中国化,它们在iOS和Android平台上使用2套UI库。

IzEfuam.jpg!web

比如Futter,在iOS上写一个Button,要用CupertinoButton,是iOS风格的控件,在Android上则要用RaisedButton,是Material风格的控件。

RN也是如此,它的官方说法是:learn once,write anywhere。它都不敢说:write once,run anywhere。因为它确实要求开发者写2套代码。

中国的开发者可没有这种习惯,中国的每个开发者,为了避免用户换手机后不会用自己的app,都会使用中性的设计。

就连微信Android版,底部的Tab也是仿iOS而不是Material风格(Material风格是把底tab放在顶部的,并且左右滑动,微信曾经有这样一个临时版本,因为被用户吐槽,很快就下掉了)。

这种中外差异怎么造成的?

国外Android手机,其手机主界面就是强烈的Material风格。用户在Android主界面习惯的风格和使用方式,如果启动一个App后不是这样,会导致用户不会用了。

Google也一再给Android开发者强调,App必须使用Material风格。这其实也是一个防止用户切换脱离Android的策略设计。

所以国外开发者的App,Android上都会遵循Material风格,当然,这种Material风格的App是上不了Apple的Appstore的。

这就导致他们默认就是要写2套UI的,所以rn和flutter都是iOS、Android各自1套ui控件。

但在中国,我们的国产Android Rom,根本不是Material风格,很多ROM以仿iOS体验为卖点。

所以中国的App,全都是贴近iOS的中性风格,中国的用户换了手机,不管是手机OS本身,还是App的使用,都不会造成切换障碍。

RN和Flutter这种“跨平台”排版引擎,其跨平台性,对于中国开发者而言,又打了折扣。

其实类似小程序那样的UI风格,是能够良好的跨iOS和Android的体验的,不管用什么手机,打开小程序都不会觉得有问题。

7f2AFbB.jpg!web

uni-app默认也是这种通用UI风格。uni-app的开发者只需要写一套界面UI,就可以适应不同手机的用户, 真正的 write once,run anywhere。

动态性

Webview、RN/Weex,都有一个特点,可以远程动态载入JS代码,可以更新本地的JS代码。前端开发者认为动态性是天经地义的,但其实Flutter并不支持。

Flutter是有编译优化概念的,如果它提供动态性支持,会影响它的性能。

业内有些开发者改造了Flutter,用一个独立的V8/JSCore来加载动态JS代码去操作Flutter布局引擎的渲染。好像还有些人在追捧这样的方案,简直是闲得蛋疼。

Flutter本来没有跨环境通信的问题,结果又弄了一个JS引擎进来搞出了通信问题,造成性能下降,还把包体积增加了很大,还不如直接用RN/Weex。

除了Flutter,RN/Weex/Uni-app都可以动态热更新。

跨平台排版引擎和跨平台应用开发引擎的区别

有些人说他们的App用RN/Weex、Flutter。但是具体用它们做了什么呢?

是整个App用了它们,还是某个页面用了它们?

一个页面跨平台,和一个应用跨平台,是完全不同的2个概念。

Webview、RN/Weex、Flutter全部是渲染引擎,Webview因为HTML5的发展还算是多了一些能力比如位置服务、多媒体等。而RN/Weex、Flutter真的只是一个纯粹的排版引擎,没有任何原生能力。

如果一个原生应用里,某个不涉及原生能力的界面想跨平台,那么这几个引擎都可以,并且Flutter的性能最高。所以能看到一些公司尝试把App中的个别原生交互较少页面使用Flutter实现。

但如果一个完整的应用,想用跨平台工具开发,那就不是排版引擎的范畴了,它需要应用开发引擎。

什么是跨平台应用开发引擎?不但排版部分要跨平台,开发API也要跨平台。

应用开发离不开OS或三方SDK的能力调用,如果是单纯的排版引擎,一旦涉及OS能力和SDK调用,就必须iOS、Android的工程师配合,编写不同的原生代码整合在一起。这就不跨平台了。

Airbnb曾是 React Native 框架的倡导者和开发者代表。但他们于2019年正式发公告弃用了React Native。

原因是什么?

很简单,React Native并不能提升Airbnb的开发效率,反而降低了他们的效率。

“本来我们可以只维护Android和iOS两套代码,但现在我们要维护三套(指多了一套React Native的JS代码),这让我们很疲惫” – aribnb

开发者选用跨平台开发引擎,本来是为了提高效率、降低成本。Airbnb正是在实践了几年后,发现RN根本无法实现他选用跨平台引擎的初衷时无奈放弃了RN,用原生开发重写。

要想真的提升开发效率,降低开发成本,那么跨平台开发引擎,需要提供一个完整的应用开发平台,包含所有常用的应用开发能力的跨平台。在不常用的部分,提供插件市场以及免原生介入的插件使用方式。

在React Native、Flutter的社区,也有不少三方提供的原生插件,但是连Airbnb这样的国外开发者对此都不满意。更何况对于很多中国开发者常用的场景,其对应的插件的质量、跨端性都难以商用。

更麻烦的是如果你不会原生开发,就没法把这些插件与你的前端代码集成起来。

ZNRnMfy.jpg!web

Uni-app,它的设计目标不是跨平台排版引擎,而是跨平台应用开发引擎。

所以Uni-app的排版部分,可以选择小程序强化Webview引擎和Weex引擎,可根据自己的需求切换。而能力层面,uni-app提供了htmlplus API、Native.js、插件市场,解决了原生能力js化的问题。

uni-app让开发者真的不用懂原生开发就能做出完整的跨平台应用。遇到极个别的需求,开发者也可以去插件市场找人订做一个原生插件,自己仍然使用js来集成,仍然可以云端直接打包。

技术学习成本和难度

RN, 要求开发者学习React,要求精通Flex布局,要求原生开发协作。

Flutter,要求开发者学习Dart,了解Dart和Flutter的API、要求精通Flex布局,要求原生开发协作。

Weex,已经内嵌到uni-app中,就不单独提了。

uni-app,要求开发者学习Vue,了解小程序。

很明显uni-app的学习成本太低了,它没有附加专有技术,全部使用公共技术。

学习成本和难度,直接意味着:开发成本、招聘成本、上线速度、上线风险。

另外,Dart究竟值不值得学,是一个大问题。

Google的天才工程师也发明了Go语言,它确实有很多理论优势,但实际上市场的主流,仍然是C和C++。

生态

任何开发引擎,都离不开生态。

对于国外的开发者,RN、Flutter的生态肯定比uni-app好,比如Facebook登陆分享、Google地图等。

但对于国内的开发者,那是反过来的,中国开发者需要的全端推送(UniPush集成了iOS、华为、小米、OPPO等众多原厂推送)、各种国内登陆、支付、分享SDK、各种国内地图、各种UI库、以及Echart图表等,都是在uni-app体系里,这方面生态可比RN、Flutter丰富多了。

其他端的跨端性

Flutter 和 RN 都是支持Web技术的。但都是仅限于普通界面排版,涉及定位、摄像头、相册什么的,是要单独写代码的。

另外Flutter的H5版,嗯,作为中国开发者,你不会想要一个如此浓郁的Material风格的H5版的。。。

更何况这个 Material UI 库大的很,编译出来的H5版要十几M的体积。

uni-app的H5端是包含完善的能力引擎的,丰富能力都可以直接跨端使用,风格也是跨端风格。uni-app的H5引擎体积只有100K,Gzip后只剩下30k(不含Vue、Vue Router),比其他工具的引擎体积要小的多。

另外,中国离不开小程序,RN、Flutter 官方都不会支持小程序,由于架构差异太大,国内三方也做不到把RN代码良好的编译为小程序代码。uni-app则可以一套代码,同时编译为iOS、Android、H5、微信小程序、支付宝小程序、百度小程序、头条小程序、QQ小程序。 结论

每种技术的诞生,有其背后公司的目的。

但凡没有明确公司战略的技术,除非是特别简单的技术,否则很难商用,因为为了商用要投入公司非常多资源。

Flutter诞生的目的是为了 Fuchsia OS,是为了在下一个互联网大潮即万物互联的物联网年代,提供一个类似Android在移动互联网位置的垄断性操作系统。

因为Google已经很明确不会在下一个时代使用Android+Java的路线了。

至于在Android上去Java化,那是Kotlin的使命,与Flutter无关。

跨iOS和Android平台开发,这不是Google的战略目标。

但万物互联何时到来?Fuchsia OS 何时流行?这在现实中是一个问号,在Google内部,也只是战略储备项目。

一个语言的流行,不是一件简单的事情,不是有优点,就会流行,它需要天时地利人和。

6年前我们就知道Dart比JS更好,Dart不应该消亡,但想成为主流技术太难太难了。

同样我们也知道Go比C++更好,但Go还是起不来。

想靠Flutter驱动Dart流行是不现实的,甚至是反过来的。跨iOS、Android开发在国外不是主流市场,这点价值造就不出一个这么难建的生态。

所以Dart能否流行,是要打一个大大的问号的,它可能会像Go语言一样,叫好不叫座。

Flutter VS Uni-app

Flutter的相对优势:性能好一丢丢。比RN有优势,但比拥有Bindingx的Weex/uni-app,在实际开发中没有很明显的差距。

Flutter的相对劣势:

  • 需要原生协作,维护3套代码,无法有效降低开发成本,提升开发效率

  • 嵌套地狱,代码难看难维护

  • 不支持热更新

  • 目前质量和成熟度很低,Github上的issue有5k+,很容易掉坑里

  • 原生可视控件融合不好,比如webview、video、map

  • UI库不适合国情

  • 学习成本高

  • Dart未来扑朔迷离

RN VS Uni-app

RN的相对优势:

  • RN的坑虽然比Weex的少,但uni-app已经填了Weex的很多坑。这方面差别不大。

  • RN的生态虽然比Weex丰富。但uni-app是反过来的,uni-app的国内应用生态丰富度超过了RN。

  • RN的app冷启动比uni-app快。这个问题uni-app已经内部改进完毕,下个版本发布就能解决。

  • RN是纯单页的,嵌入原生App比较灵活。而uni-app是应用整体的概念,如果要内嵌入其他原生应用的话,要求原生应用内嵌uni-app应用整体进来。

RN的相对劣势:

  • 需要原生协作,维护3套代码,无法有效降低开发成本,提升开发效率。

  • 不支持小程序,发布到H5也无法直接发。

  • UI库不适合国情,learn once,write anywhere。

  • 学习成本高,用人成本高,不利于开发商降低开发成本。

  • RN是纯单页应用,如果一个应用的页面很多,用RN写会很崩溃,变量污染和干扰严重。而Weex/uni-app支持多页面,页面之间上下文隔离,写页面较多的大型应用更合适。

  • 另外React在中国的市场占有率远不如Vue。这也是中国与国外不同的特色情况。

贴个Vue、React、React Native的百度指数对比,无论总体量的差距,还是发展趋势的下滑程度,可以明显看出React系在中国确实不行了。

RVRRbiM.png!web 最上面的时Vue

中国的开发者,过去总会想:

  1. 小程序那套Webview优化的技术,我能不能用到我的App里?现在uni-app已经为你解决了这个问题。

  2. Weex能不能坑少点,API和插件多点?现在uni-app已经为你解决了这个问题。

如果你是一个资源充沛的大公司,原生App中部分不要求动态性、也没有太多原生交互的页面,可以尝试使用Flutter实现。但如果大范围使用,你也会遇到和Airbnb一样的问题,维护3套代码还不如维护2套代码。

如果你开发uni-app选用了Weex原生渲染,那App的性能足够好,且你得到了切实的开发效率的提升、成本的下降、快速和低风险的上线。

选择跨平台工具而不是原生开发,本质目的不就是为了成本和效率吗?能真正解决你本质需求的,就是uni-app。

推荐阅读

·  玩转 Terminal 终端:入门指南及进阶技巧

·  6个很棒的Webpack插件提高您的生产力

·  Next.js和Nuxt.js的语法比较

·  新手React开发人员容易做错的5件事

·  Chrome浏览器终可以对标签进行整理和分组了

·  7个很棒的JavaScript产品步骤引导库

·  2020年排名前11位的静态网站生成器

·  让你在2020年成为前端大师的9个项目

fIjyM3R.png!web

点个再看呗


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK