每當咱們評估新技術時要問的第一個問題就是「它會給咱們的業務和客戶帶來哪些價值?」,工程師們很容易對閃閃發光的新事物着迷,卻常常會忽略這些新事物其實可能對咱們的客戶沒有任何好處,反而只會讓現有的工做流程更加複雜。javascript
flutter最近比較熱鬧,畢竟是Google出品。css
但咱們不是炒做熱點的媒體,也不是忽悠你交學費的培訓機構,咱們做爲實際的跨平臺開發者,冷靜的分析下這個東東。html
flutter是Google爲Fuchsia操做系統設計的應用開發方式。前端
Fuchsia OS要兼容廉價物聯網設備,要求對硬件的消耗下降,而且爲了不與oracle的java打官司,Fuchsia 使用了dart語言+flutter界面庫的方式。vue
從設計上來看,這套方案的性能確實夠高。dart雖然屬於大前端範疇,但dart是和java同樣的強類型語言,這讓dart虛擬機能夠作不少優化,性能方面超出了js。java
dart曾經與typescript競爭,誰纔是更好的js?但不幸輸給了typescript,chrome也放棄了內置dart虛擬機的計劃。react
不過dart團隊沒有解散,幾年後,他們藉助flutter,再次出如今公衆面前。css3
flutter做爲界面庫(注意它只是界面庫,dart語言是另外一個項目),它惟一要乾的事情就是渲染界面。不像HTML5,flutter界面庫連視頻、定位等都沒有,就是一個純排版引擎,繪製文字、按鈕、圖片等經常使用界面控件。c++
這個排版引擎的特色是簡單、高性能。git
在3大主流渲染引擎裏,webview、react native/weex、flutter,複雜度依次下降,渲染性能依次上升。(uni-app是雙渲染引擎,webview和weex都內置了,隨便開發者使用切換)
因此咱們要清楚,提高性能是有代價的,你究竟想要靈活豐富的css3,仍是想要固定flex模式排版,抑或是最簡單但高性能的flutter排版?開發便利性和運行性能不可兼得。
同時咱們要明白,性能的差異,並非由於Google的chrome團隊、Android團隊的技術比同公司的flutter團隊差。而是flutter提供的佈局寫法是被限制過的,解析快,因此渲染快。別忘了webview的排版引擎也是世界級工程師用c寫的。
但經過這種方式提高性能的代價,就是佈局複雜的界面時,flutter的代碼嵌套的讓人崩潰。
咱們先舉個例子,一樣的界面,用HTML和flutter如何實現:
複製代碼<div class="greybox"> <div class=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 }
複製代碼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和原生通訊慢。
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代碼,也是預載好的。因此點擊新頁面時,它的渲染速度和原生應用沒什麼差異。固然也有個壞處,就是啓動慢。微信裏啓動小程序速度看着還行,實際上是微信在啓動小程序以前,就已經提早初始化了小程序運行環境。
無論是rn仍是flutter,有一個設計,很不中國化。它們在iOS和Android平臺上,使用2套ui庫。
好比flutter,在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的體驗的,無論用什麼手機,打開小程序都不會以爲有問題。
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這樣的國外開發者對此都不滿意。更況且對於不少中國開發者經常使用的場景,其對應的插件的質量、跨端性都難以商用。
更麻煩的是若是你不會原生開發,就無法把這些插件與你的前端代碼集成起來。
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引擎體積只有1百K,gzip後只剩下30k(不含vue、vue rooter),比其餘工具的引擎體積要小的多。
另外,中國離不開小程序,rn、flutter官方都不會支持小程序,因爲架構差別太大,國內三方也作不到把rn代碼良好的編譯爲小程序代碼。uni-app則能夠一套代碼,同時編譯爲iOS、Android、H五、微信小程序、支付寶小程序、百度小程序、頭條小程序、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與uni-app的比較:
再總結下rn和uni-app的比較
貼個vue、react、react native的百度指數對比,不管整體量的差距,仍是發展趨勢的下滑程度,能夠明顯看出react系在中國確實不行了。
中國的開發者,過去總會想:
若是你是一個資源充沛的大公司,原生App中部分不要求動態性、也沒有太多原生交互的頁面,能夠嘗試使用flutter實現。但若是大範圍使用,你也會遇到和aribnb同樣的問題,維護3套代碼還不如維護2套代碼。
若是你開發uni-app選用了weex原生渲染,那App的性能足夠好,且你獲得了切實的開發效率的提高、成本的降低、快速和低風險的上線。
選擇跨平臺工具而不是原生開發,本質目的不就是爲了成本和效率嗎?能真正解決你本質需求的,就是uni-app。