本文是转DCloud社区里开源作者DCloud_heavensoft 一篇关于对跨平台开发技术路线方案比较的文章,分别对现今较为热门的跨平台方案flutter、react native、uni-app进行比较。
原文链接
每当我们评估新技术时要问的第一个问题就是“它会给我们的业务和客户带来哪些价值?”,工程师们很容易对闪闪发光的新事物着迷,却经常会忽略这些新事物其实可能对我们的客户没有任何好处,反而只会让现有的工作流程更加复杂。
flutter最近比较热闹,毕竟是Google出品。
但我们不是炒作热点的媒体,也不是忽悠你交学费的培训机构,我们作为实际的跨平台开发者,冷静的分析下这个东东。
flutter是Google为Fuchsia操作系统设计的应用开发方式。
Fuchsia OS要兼容廉价物联网设备,要求对硬件的消耗降低,并且为了避免与oracle的java打官司,Fuchsia 使用了dart语言+flutter界面库的方式。
从设计上来看,这套方案的性能确实够高。dart虽然属于大前端范畴,但dart是和java一样的强类型语言,这让dart虚拟机可以做很多优化,性能方面超出了js。
dart曾经与typescript竞争,谁才是更好的js?但不幸输给了typescript,chrome也放弃了内置dart虚拟机的计划。
不过dart团队没有解散,几年后,他们借助flutter,再次出现在公众面前。
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&#61;"greybox"> <div class&#61;redbox> smaple text div>
div> .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
}
Flutter&#xff1a;
var container &#61; 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],
);
可以看出&#xff0c;从代码的写法来说&#xff0c;flutter没有tag和样式的说法&#xff0c;更没有选择器&#xff0c;从头到尾只有dart语言&#xff0c;它的界面控件是用dart代码new出来的&#xff0c;每个控件的样式&#xff0c;是在new的时候设置的json参数。
如果我们要嵌套布局&#xff0c;就要不停的在dart里写child&#xff0c;同时在dart里给child们设样式参数。上面的代码&#xff0c;只是嵌套了1层&#xff0c;实际开发中&#xff0c;dom要嵌套好多层&#xff0c;想象那样的代码。。。所以大家都诟病dart是“嵌套地狱”。
或者&#xff0c;你可以这么理解&#xff0c;这是一个只有js&#xff0c;没有html和css的浏览器。你需要用js createElement来创建元素&#xff0c;用js的style方法给每个element设style&#xff0c;反正就是不能写html和css代码。前端都已经发展到各种mvc等视图逻辑分离的架构了&#xff0c;也有了vue组件这种组件化模式方便用各种轮子快速完成界面。你是否能适应dart这种低效的界面开发模式&#xff1f;从开发模式来讲&#xff0c;这确实是一种倒退。
浏览器的html提供了tag和样式分离的写法&#xff0c;还有各种各样的选择器&#xff0c;但其实这也是有代价的。它导致webview初始化时要同时先启动webkit排版引擎来解析这些编写随性的html、css&#xff0c;同时还要启动一个js引擎比如v8或jscore来解析里面的js。
而dart就很简单&#xff0c;只启动一个dart引擎&#xff0c;解析严格的dart语法&#xff0c;它不会去操心有些标签未闭合要如何容错&#xff0c;不会判断宽度320后面是px还是rem或者是动态计算百分比。
对比这2个引擎初始化时要干的事&#xff0c;差别简直太大了。
所以从解析效率上&#xff0c;flutter肯定比webview要高。但从编码灵活性上&#xff0c;flutter写的代码&#xff0c;嗯&#xff0c;难看而低效&#xff01;
flutter使用的也是flex布局思想&#xff0c;这是一个强嵌套布局模型&#xff0c;比web常规排版引擎的嵌套更多。当界面复杂时&#xff0c;flutter的代码要嵌套几十层&#xff0c;每层的元素的json样式都和元素一起混写在dart代码里&#xff0c;让人崩溃。
有人提出是否可以通过一种预编译的dsl来简化写法&#xff0c;让flutter的开发不这么痛苦。
但这个难度太大了&#xff0c;从严格转换为松散是简单的&#xff0c;从松散转换为严格几乎是不可能的。
什么意思呢&#xff1f;比如flutter代码转换web代码&#xff0c;是很简单的&#xff0c;flutter已经自带了这个功能。但是想反过来&#xff0c;那可难了。
类似的还有&#xff0c;把typescript转为js是容易的&#xff0c;反之&#xff0c;不是绝对不可行&#xff0c;但会复杂到你宁愿去重写一套typescript代码。
flutter的性能高&#xff0c;除了简单严格&#xff0c;还有一个特点&#xff0c;就是逻辑层与视图层统一&#xff0c;运行在同一套dart虚拟机下。
我们知道rn和weex&#xff0c;也是原生渲染的&#xff0c;它们的性能高于webview。但同为原生渲染的&#xff0c;怎么会慢于flutter呢&#xff1f;其实不是原生渲染慢&#xff0c;而是js和原生通信慢。
rn和weex都采用了独立的js引擎&#xff08;iOS是jscore&#xff0c;Android是v8&#xff0c;最新版rn开始在Android上搞自己的js引擎&#xff09;&#xff0c;从js与dart的比较上&#xff0c;性能稍逊一筹。但这不是主要问题&#xff0c;主要问题是&#xff0c;rn、weex的js引擎和原生渲染层是两个运行环境。
当js引擎联网获取到数据后&#xff0c;通知原生视图层更新界面时&#xff0c;有一个跨环境的通信折损。同样&#xff0c;当用户在屏幕上操作原生视图层时&#xff0c;要给js引擎发送通知&#xff0c;也会产生这个通信折损。
不过这种性能差别&#xff0c;在大多数场景中&#xff0c;用户是感受不到的。比较影响的场景&#xff0c;是跟手式的js响应操作绘制帧动画。
这方面&#xff0c;weex有个值得称赞的技术是BindingX&#xff0c;它可以预定义规则&#xff0c;让用户界面在原生层交互时通过预定义规则直接响应&#xff0c;而无需传递给js层。在需要短时间内来回通信的场景时&#xff0c;可以使用BindingX这类解决方案。它的性能和灵活性比rn更强了一些。
说回来flutter&#xff0c;它只有一个dart引擎&#xff0c;没有来回通信产生的性能问题。不过任何事情都是有利有弊的&#xff0c;flutter在普通的界面绘制上效率虽然高&#xff0c;但一旦涉及原生的界面&#xff0c;反而会遇到更多问题。
前面已经说过&#xff0c;flutter只是一个基础排版引擎&#xff0c;缺少很多能力&#xff0c;当我们需要在flutter界面上内嵌一个原生的视频播放扩展控件时&#xff08;flutter没有视频播放能力&#xff09;&#xff0c;或者原生的高德地图sdk&#xff0c;那么在拖动视频进度时、拖动地图时&#xff0c;flutter一样会产生原生和dart之间的通信&#xff0c;造成性能损耗。
事实上&#xff0c;由于flutter是在一个类canvas环境绘制的&#xff0c;想把一个原生控件嵌入flutter的布局里某些元素之间去排版&#xff0c;还不是一件容易做到的事情&#xff0c;坑很多。
每个人都想要一个像css3那样灵活写法的布局引擎&#xff0c;他们给react native和weex提需求&#xff0c;给flutter提需求。殊不知&#xff0c;让这些产品团队实现了css3时&#xff0c;他们的性能优势已经不再了&#xff0c;他们相当于又实现了一遍webview。这种无意义的需求&#xff0c;他们是不会受理了。
性能好&#xff0c;有个度&#xff0c;客观地讲&#xff0c;rn/weex调用原生渲染的性能&#xff0c;和flutter的渲染性能&#xff0c;在用户体验上并没有明显区别&#xff0c;甚至在很多场景下&#xff0c;和webview渲染的小程序也没有明显区别。
也简单说说webview渲染小程序&#xff0c;为什么性能高&#xff0c;核心是预载。点击一个新页面时&#xff0c;webview是提前创建好的&#xff0c;不会走复杂的webkit、v8的初始化流程&#xff0c;连开发者的js代码&#xff0c;也是预载好的。所以点击新页面时&#xff0c;它的渲染速度和原生应用没什么差别。当然也有个坏处&#xff0c;就是启动慢。微信里启动小程序速度看着还行&#xff0c;其实是微信在启动小程序之前&#xff0c;就已经提前初始化了小程序运行环境。
不管是rn还是flutter&#xff0c;有一个设计&#xff0c;很不中国化。它们在iOS和Android平台上&#xff0c;使用2套ui库。
比如flutter&#xff0c;在iOS上写一个button&#xff0c;要用CupertinoButton&#xff0c;是iOS风格的控件&#xff0c;在Android上则要用RaisedButton&#xff0c;是Material风格的控件。
rn也是如此&#xff0c;它的官方说法是&#xff1a;learn once&#xff0c;write anywhere。它都不敢说&#xff1a;write once&#xff0c;run anywhere。因为它确实要求开发者写2套代码。
中国的开发者可没有这种习惯&#xff0c;中国的每个开发者&#xff0c;为了避免用户换手机后不会用自己的app&#xff0c;都会使用中性的设计。
就连微信Android版&#xff0c;底部的tab也是仿iOS而不是Material风格&#xff08;Material风格是把底tab放在顶部的&#xff0c;并且左右滑动&#xff0c;微信曾经有这样一个临时版本&#xff0c;因为被用户吐槽&#xff0c;很快就下掉了&#xff09;。
这种中外差异怎么造成的&#xff1f;
国外Android手机&#xff0c;其手机主界面就是强烈的Material风格。用户在Android主界面习惯的风格和使用方式&#xff0c;如果启动一个App后不是这样&#xff0c;会导致用户不会用了。
Google也一再给Android开发者强调&#xff0c;App必须使用Material风格。这其实也是一个防止用户切换脱离Android的策略设计。
所以国外开发者的App&#xff0c;Android上都会遵循Material风格&#xff0c;当然&#xff0c;这种Material风格的App是上不了Apple的Appstore的。
这就导致他们默认就是要写2套ui的&#xff0c;所以rn和flutter都是iOS、Android各自1套ui控件。
但在中国&#xff0c;我们的国产Android Rom&#xff0c;根本不是Material风格&#xff0c;很多rom以仿iOS体验为卖点。
所以中国的App&#xff0c;全都是贴近iOS的中性风格&#xff0c;中国的用户换了手机&#xff0c;不管是手机os本身&#xff0c;还是App的使用&#xff0c;都不会造成切换障碍。
rn和flutter这种“跨平台”排版引擎&#xff0c;其跨平台性&#xff0c;对于中国开发者而言&#xff0c;又打了折扣。
其实类似小程序那样的ui风格&#xff0c;是能够良好的跨iOS和Android的体验的&#xff0c;不管用什么手机&#xff0c;打开小程序都不会觉得有问题。
uni-app默认也是这种通用ui风格。uni-app的开发者只需要写一套界面ui&#xff0c;就可以适应不同手机的用户&#xff0c;真正的 write once&#xff0c;run anywhere。
webview、rn/weex&#xff0c;都有一个特点&#xff0c;可以远程动态载入js代码&#xff0c;可以更新本地的js代码。前端开发者认为动态性是天经地义的&#xff0c;但其实flutter并不支持。
flutter是有编译优化概念的&#xff0c;如果它提供动态性支持&#xff0c;会影响它的性能。
业内有些开发者&#xff0c;改造了flutter&#xff0c;用一个独立的v8/jscore来加载动态js代码&#xff0c;去操作flutter布局引擎的渲染。好像还有些人在追捧这样的方案&#xff0c;简直是闲得蛋疼。
flutter本来没有跨环境通信的问题&#xff0c;结果又弄了一个js引擎进来搞出了通信问题&#xff0c;造成性能下降&#xff0c;还把包体积增加了很大&#xff0c;还不如直接用rn/weex。
除了flutter&#xff0c;rn/weex/uni-app都可以动态热更新。
有些人说他们的App用rn/weex、flutter。但是具体用它们做了什么呢&#xff1f;
是整个App用了它们&#xff0c;还是某个页面用了它们&#xff1f;
一个页面跨平台&#xff0c;和一个应用跨平台&#xff0c;是完全不同的2个概念。
webview、rn/weex、flutter全部是渲染引擎&#xff0c;webview因为HTML5的发展&#xff0c;还算是多了一些能力比如位置服务、多媒体等。而rn/weex、flutter真的只是一个纯粹的排版引擎&#xff0c;没有任何原生能力。
如果一个原生应用里&#xff0c;某个不涉及原生能力的界面想跨平台&#xff0c;那么这几个引擎都可以&#xff0c;并且flutter的性能最高。所以能看到一些公司尝试把App中的个别原生交互较少页面使用flutter实现。
但如果一个完整的应用&#xff0c;想用跨平台工具开发&#xff0c;那就不是排版引擎的范畴了&#xff0c;它需要应用开发引擎。
什么是跨平台应用开发引擎&#xff1f;不但排版部分要跨平台&#xff0c;开发API也要跨平台。
应用开发离不开os或三方sdk的能力调用&#xff0c;如果是单纯的排版引擎&#xff0c;一旦涉及os能力和sdk调用&#xff0c;就必须iOS、Android的工程师配合&#xff0c;编写不同的原生代码整合在一起。这就不跨平台了。
Airbnb曾是React Native 框架的倡导者和开发者代表。但他们于2019年正式发公告&#xff0c;弃用了react native。
原因是什么&#xff1f;
很简单&#xff0c;react native并不能提升Airbnb的开发效率&#xff0c;反而降低了他们的效率。
“本来我们可以只维护Android和iOS两套代码&#xff0c;但现在我们要维护三套&#xff08;指多了一套react native的js代码&#xff09;&#xff0c;这让我们很疲惫” – aribnb
开发者选用跨平台开发引擎&#xff0c;本来是为了提高效率、降低成本。Airbnb正是在实践了几年后&#xff0c;发现rn根本无法实现他选用跨平台引擎的初衷时&#xff0c;无奈放弃了rn&#xff0c;用原生开发重写。
要想真的提升开发效率&#xff0c;降低开发成本&#xff0c;那么跨平台开发引擎&#xff0c;需要提供一个完整的应用开发平台&#xff0c;包含所有常用的应用开发能力的跨平台。在不常用的部分&#xff0c;提供插件市场以及免原生介入的插件使用方式。
在react native、flutter的社区&#xff0c;也有不少三方提供的原生插件&#xff0c;但是连Airbnb这样的国外开发者对此都不满意。更何况对于很多中国开发者常用的场景&#xff0c;其对应的插件的质量、跨端性都难以商用。
更麻烦的是如果你不会原生开发&#xff0c;就没法把这些插件与你的前端代码集成起来。
uni-app&#xff0c;它的设计目标不是跨平台排版引擎&#xff0c;而是跨平台应用开发引擎。
所以uni-app的排版部分&#xff0c;可以选择小程序强化webview引擎和weex引擎&#xff0c;可根据自己的需求切换。而能力层面&#xff0c;uni-app提供了htmlplus API、Native.js、插件市场&#xff0c;解决了原生能力js化的问题。
uni-app让开发者真的不用懂原生开发就能做出完整的跨平台应用。遇到极个别的需求&#xff0c;开发者也可以去插件市场找人订做一个原生插件&#xff0c;自己仍然使用js来集成&#xff0c;仍然可以云端直接打包。
rn&#xff0c;要求开发者学习react&#xff0c;要求精通flex布局&#xff0c;要求原生开发协作。
flutter&#xff0c;要求开发者学习dart&#xff0c;了解dart和flutter的API、要求精通flex布局&#xff0c;要求原生开发协作。
weex已经内嵌到uni-app中&#xff0c;就不单独提了。
uni-app&#xff0c;要求开发者学习vue&#xff0c;了解小程序。
很明显uni-app的学习成本太低了&#xff0c;它没有附加专有技术&#xff0c;全部使用公共技术。
学习成本和难度&#xff0c;直接意味着&#xff1a;开发成本、招聘成本、上线速度、上线风险。
另外&#xff0c;dart究竟值不值得学&#xff0c;是一个大问题。
Google的天才工程师也发明了go语言&#xff0c;它确实有很多理论优势&#xff0c;但实际上市场的主流&#xff0c;仍然是c和c&#43;&#43;。
任何开发引擎&#xff0c;都离不开生态。
对于国外的开发者&#xff0c;rn、flutter的生态肯定比uni-app好&#xff0c;比如facebook登陆分享、Google地图等。
但对于国内的开发者&#xff0c;那是反过来的&#xff0c;中国开发者需要的全端推送&#xff08;UniPush集成了iOS、华为、小米、OPPO等众多原厂推送&#xff09;、各种国内登陆、支付、分享SDK、各种国内地图、各种ui库、以及Echart图表等&#xff0c;都是在uni-app体系里&#xff0c;这方面生态可比rn、flutter丰富多了。
flutter和rn&#xff0c;都是支持web技术的。但都是仅限于普通界面排版&#xff0c;涉及定位、摄像头、相册什么的&#xff0c;是要单独写代码的。
另外flutter的H5版&#xff0c;嗯&#xff0c;作为中国开发者&#xff0c;你不会想要一个如此浓郁的Material风格的H5版的。。。
更何况这个Material ui库大的很&#xff0c;编译出来的H5版要十几M的体积。
uni-app的H5端是包含完善的能力引擎的&#xff0c;丰富能力都可以直接跨端使用&#xff0c;风格也是跨端风格。uni-app的H5引擎体积只有1百K&#xff0c;gzip后只剩下30k&#xff08;不含vue、vue rooter&#xff09;&#xff0c;比其他工具的引擎体积要小的多。
另外&#xff0c;中国离不开小程序&#xff0c;rn、flutter官方都不会支持小程序&#xff0c;由于架构差异太大&#xff0c;国内三方也做不到把rn代码良好的编译为小程序代码。uni-app则可以一套代码&#xff0c;同时编译为iOS、Android、H5、微信小程序、支付宝小程序、百度小程序、头条小程序、QQ小程序。
每种技术的诞生&#xff0c;有其背后公司的目的。
但凡没有明确公司战略的技术&#xff0c;除非是特别简单的技术&#xff0c;否则很难商用&#xff0c;因为为了商用要投入公司非常多资源。
flutter诞生的目的&#xff0c;是为了Fuchsia OS&#xff0c;是为了在下一个互联网大潮&#xff0c;即万物互联的物联网年代&#xff0c;提供一个类似Android在移动互联网位置的垄断性操作系统。
因为Google已经很明确不会在下一个时代使用Android&#43;java的路线了。
至于在Android上去java化&#xff0c;那是Kotlin的使命&#xff0c;与flutter无关。
跨iOS和Android平台开发&#xff0c;这不是Google的战略目标。
但万物互联何时到来&#xff1f;Fuchsia OS何时流行&#xff1f;这在现实中是一个问号&#xff0c;在Google内部&#xff0c;也只是战略储备项目。
一个语言的流行&#xff0c;不是一件简单的事情&#xff0c;不是有优点&#xff0c;就会流行&#xff0c;它需要天时地利人和。
6年前我们就知道dart比js更好&#xff0c;dart不应该消亡&#xff0c;但想成为主流技术&#xff0c;太难太难了。
同样我们也知道go比c&#43;&#43;更好&#xff0c;但go还是起不来。
想靠flutter驱动dart流行是不现实的&#xff0c;甚至是反过来的。跨iOS、Android开发在国外不是主流市场&#xff0c;这点价值造就不出一个这么难建的生态。
所以dart能否流行&#xff0c;是要打一个大大的问号的&#xff0c;它可能会像go语言一样&#xff0c;叫好不叫座。
写了这么多&#xff0c;最后总结下flutter与uni-app的比较&#xff1a;
再总结下rn和uni-app的比较
贴个vue、react、react native的百度指数对比&#xff0c;无论总体量的差距&#xff0c;还是发展趋势的下滑程度&#xff0c;可以明显看出react系在中国确实不行了。
中国的开发者&#xff0c;过去总会想&#xff1a;
小程序那套webview优化的技术&#xff0c;我能不能用到我的App里&#xff1f;现在uni-app已经为你解决了这个问题。
weex能不能坑少点&#xff0c;API和插件多点&#xff1f;现在uni-app已经为你解决了这个问题。
如果你是一个资源充沛的大公司&#xff0c;原生App中部分不要求动态性、也没有太多原生交互的页面&#xff0c;可以尝试使用flutter实现。但如果大范围使用&#xff0c;你也会遇到和aribnb一样的问题&#xff0c;维护3套代码还不如维护2套代码。
如果你开发uni-app选用了weex原生渲染&#xff0c;那App的性能足够好&#xff0c;且你得到了切实的开发效率的提升、成本的下降、快速和低风险的上线。
选择跨平台工具而不是原生开发&#xff0c;本质目的不就是为了成本和效率吗&#xff1f;能真正解决你本质需求的&#xff0c;就是uni-app。