全網(wǎng)最全 Flutter 與 React Native 深入對(duì)比分析

作為 GSY 開(kāi)源系列的作者镰吆,在去年也整理過(guò) 《移動(dòng)端跨平臺(tái)開(kāi)發(fā)的深度解析》 的對(duì)比文章,時(shí)隔一年之后跑慕,本篇將重新由 環(huán)境搭建万皿、實(shí)現(xiàn)原理、編程開(kāi)發(fā)核行、插件開(kāi)發(fā)牢硅、編譯運(yùn)行、性能穩(wěn)定芝雪、發(fā)展未來(lái) 等七個(gè)方面减余,對(duì)當(dāng)前的 React NativeFlutter 進(jìn)行全面的分析對(duì)比,希望能給你更有價(jià)值的參考惩系。

是的位岔,這次沒(méi)有了 Weex,超長(zhǎng)內(nèi)容預(yù)警堡牡,建議收藏后閱抒抬。

前言

臨冬之際,移動(dòng)端跨平臺(tái)在經(jīng)歷數(shù)年沉浮之后晤柄,如今還能在舞臺(tái)聚光燈下雀躍的擦剑, 也只剩下 React NativeFlutter 了,作為沉淀了數(shù)年的 “豪門(mén)” 與 19 年當(dāng)紅的 “新貴” 芥颈,它們之間的 “針?shù)h相對(duì)” 也成了開(kāi)發(fā)者們關(guān)心的事情惠勒。

過(guò)去曾有人問(wèn)我:“他即寫(xiě) Java 又會(huì) Object-C ,在 Android 和 IOS 平臺(tái)上可以同時(shí)開(kāi)發(fā)爬坑,為什么還要學(xué)跨平臺(tái)呢纠屋?”

而我的回答是:跨平臺(tái)的市場(chǎng)優(yōu)勢(shì)不在于性能或?qū)W習(xí)成本,甚至平臺(tái)適配會(huì)更耗費(fèi)時(shí)間妇垢,但是它最終能讓代碼邏輯(特別是業(yè)務(wù)邏輯)巾遭,無(wú)縫的復(fù)用在各個(gè)平臺(tái)上肉康,降低了重復(fù)代碼的維護(hù)成本闯估,保證了各平臺(tái)間的統(tǒng)一性, 如果這時(shí)候還能保證一定的性能吼和,那就更完美了涨薪。

類(lèi)型 React Native Flutter
語(yǔ)言 JavaScript dart
環(huán)境 JSCore Flutter Engine
發(fā)布時(shí)間 2015 2017
star 78k+ 67k+
對(duì)比版本 0.59.9 1.6.3
空項(xiàng)目打包大小 Android 20M(可調(diào)整至 7.3M) / IOS 1.6M Android 5.2M / IOS 10.1M
GSY項(xiàng)目大小 Android 28.6M / IOS 9.1M Android 11.6M / IOS 21.5M
代碼產(chǎn)物 JS Bundle 文件 二進(jìn)制文件
維護(hù)者 Facebook Google
風(fēng)格 響應(yīng)式,Learn once, write anywhere 響應(yīng)式炫乓,一次編寫(xiě)多平臺(tái)運(yùn)行
支持 Android刚夺、IOS献丑、(PC) Android、IOS侠姑、(Web/PC)
使用代表 京東创橄、攜程、騰訊課堂 閑魚(yú)莽红、美團(tuán)B端

一妥畏、環(huán)境搭建

無(wú)論是 React Native 還是 Flutter ,都需要 AndroidIOS 的開(kāi)發(fā)環(huán)境安吁,也就是 JDK 醉蚁、Android SDK、Xcode 等環(huán)境配置鬼店,而不同點(diǎn)在于 :

  • React Native 需要 npm 网棍、nodereact-native-cli 等配置 妇智。
  • Flutter 需要 flutter sdkAndroid Studio / VSCode 上的 DartFlutter 插件滥玷。

從配置環(huán)境上看, Flutter 的環(huán)境搭配相對(duì)簡(jiǎn)單巍棱,而 React Native 的環(huán)境配置相對(duì)復(fù)雜罗捎,而且由于 node_module 的“黑洞”屬性和依賴(lài)復(fù)雜度等原因,目前在個(gè)人接觸的例子中拉盾,首次配置運(yùn)行成功率 Flutter 是高于 React Native 的桨菜,且 Flutter 失敗的原因則大多歸咎于網(wǎng)絡(luò)。

同時(shí)跨平臺(tái)開(kāi)發(fā)首選 Mac 捉偏,沒(méi)有為什么倒得。

二、實(shí)現(xiàn)原理

AndroidIOS 上夭禽,默認(rèn)情況下 FlutterReact Native需要一個(gè)原生平臺(tái)的
Activity / ViewController 支持霞掺,且在原生層面屬于一個(gè)“單頁(yè)面應(yīng)用”,
而它們之間最大的不同點(diǎn)其實(shí)在于 UI 構(gòu)建 :

  • React Native

React Native 是一套 UI 框架讹躯,默認(rèn)情況下 React Native 會(huì)在 Activity 下加載 JS 文件菩彬,然后運(yùn)行在 JavaScriptCore 中解析 Bundle 文件布局,最終堆疊出一系列的原生控件進(jìn)行渲染潮梯。

簡(jiǎn)單來(lái)說(shuō)就是 通過(guò)寫(xiě) JS 代碼配置頁(yè)面布局骗灶,然后 React Native 最終會(huì)解析渲染成原生控件,如 <View> 標(biāo)簽對(duì)應(yīng) ViewGroup/UIView 秉馏,<ScrollView> 標(biāo)簽對(duì)應(yīng) ScrollView/UIScrollView 耙旦,<Image> 標(biāo)簽對(duì)應(yīng) ImageView/UIImageView 等。

所以相較于如 Ionic 等框架而言萝究, React Native 讓頁(yè)面的性能能得到進(jìn)一步的提升免都。

  • Flutter

如果說(shuō) React Native 是為開(kāi)發(fā)者做了平臺(tái)兼容锉罐,那 Flutter 則更像是為開(kāi)發(fā)者屏蔽平臺(tái)的概念。

Flutter 中只需平臺(tái)提供一個(gè) Surface 和一個(gè) Canvas 绕娘,剩下的 Flutter 說(shuō):“你可以躺下了脓规,我們來(lái)自己動(dòng)”。

Flutter 中絕大部分的 Widget 都與平臺(tái)無(wú)關(guān)险领, 開(kāi)發(fā)者基于 Framework 開(kāi)發(fā) App 抖拦,而 Framework 運(yùn)行在 Engine 之上,由 Engine 進(jìn)行適配和跨平臺(tái)支持舷暮。這個(gè)跨平臺(tái)的支持過(guò)程态罪,其實(shí)就是將 Flutter UI 中的 Widget “數(shù)據(jù)化” ,然后通過(guò) Engine 上的 Skia 直接繪制到屏幕上 下面。

所以從以上可以看出:React Native 的 Learn once, write anywhere 的思路复颈,就是只要你會(huì) React ,那么你可以用寫(xiě) React 的方式沥割,再去開(kāi)發(fā)一個(gè)性能不錯(cuò)的App耗啦;而 Flutter 則是讓你忘掉平臺(tái),專(zhuān)注于 Flutter UI 就好了机杜。

  • DOM:

額外補(bǔ)充一點(diǎn)帜讲,React 的虛擬 DOM 的概念相信大家都知道,這是 React 的性能保證之一椒拗,而 Flutter 其實(shí)也存在類(lèi)似的虛擬 DOM 概念似将。

看過(guò)我 Flutter 系列文章可能知道,Flutter 中我們寫(xiě)的 Widget 蚀苛, 其實(shí)并非真正的渲染控件在验,這一點(diǎn)和 React Native 中的標(biāo)簽類(lèi)似,Widget 更像配置文件堵未, 由它組成的 Widget 樹(shù)并非真正的渲染樹(shù)腋舌。

Widget 在渲染時(shí)會(huì)經(jīng)過(guò) Element 變化, 最后轉(zhuǎn)化為 RenderObject 再進(jìn)行繪制渗蟹, 而最終組成的 RenderObject 樹(shù)才是 “真正的渲染 Dom” 块饺, 每次 Widget 樹(shù)觸發(fā)的改變,并不一定會(huì)導(dǎo)致RenderObject 樹(shù)的完全更新雌芽。

所以在實(shí)現(xiàn)原理上 React Native 和 Flutter 是完全不同的思路授艰,雖然都有類(lèi)似“虛擬 DOM 的概念” ,但是React Native 帶有較強(qiáng)的平臺(tái)關(guān)聯(lián)性膘怕,而 Flutter UI 的平臺(tái)關(guān)聯(lián)性十分薄弱想诅。

三、 編程開(kāi)發(fā)

React Native 使用的 JavaScript 相信大家都不陌生岛心,已經(jīng) 24 歲的它在多年的發(fā)展過(guò)程中来破,各端各平臺(tái)中都出沒(méi)著它的身影,在 Facebook 的 React 開(kāi)始風(fēng)靡之后忘古,15 年移動(dòng)浪潮下推出的 React Native 徘禁,讓前端的 JS 開(kāi)發(fā)者擁有了技能的拓展。

Flutter 的首選語(yǔ)言 Dart 語(yǔ)言誕生于 2011 年髓堪,而 2018 年才發(fā)布了 2.0送朱,原本是為了用來(lái)對(duì)抗 JavaScript 而發(fā)布的開(kāi)發(fā)語(yǔ)言,卻在 Web 端一直不溫不火干旁,直到 17年 才因?yàn)?Flutter 而受關(guān)注起來(lái)驶沼,之后又因?yàn)?Flutter For Web 繼續(xù)嘗試后回歸 Web 領(lǐng)域。

編程開(kāi)發(fā)所涉及的點(diǎn)較多争群,后面主要從 開(kāi)發(fā)語(yǔ)言 回怜、界面開(kāi)發(fā)狀態(tài)管理 换薄、原生控件 四個(gè)方面進(jìn)行對(duì)比介紹玉雾。

至于最多吐槽之一就是為什么 Flutter 團(tuán)隊(duì)不選擇 JS ,有說(shuō)因?yàn)?Dart 團(tuán)隊(duì)就在 Flutter 團(tuán)隊(duì)隔壁轻要,也有說(shuō)谷歌不想和 Oracle 相關(guān)的東西沾上邊复旬。
同時(shí) React Native 更新快 4 年了,版本號(hào)依舊沒(méi)有突破 1.0 冲泥。

3.1驹碍、 語(yǔ)言

因?yàn)槠鸪醵际菫榱?Web 而生,所以 DartJS 在一定程度上有很大的通識(shí)性凡恍。

如下代碼所示幸冻, 它們都支持通過(guò) var 定義變量,支持 async/await 語(yǔ)法糖咳焚,支持 Promise(Future) 等鏈?zhǔn)疆惒教幚砬⑺穑踔?*/yield 的語(yǔ)法糖都類(lèi)似(雖然這個(gè)對(duì)比不大準(zhǔn)確),但可以看出它們確實(shí)存在“近親關(guān)系” 革半。


/// JS

    var a = 1

    async function doSomeThing() {
        var result = await xxxx()
        doAsync().then((res) => {
            console.log("ffff")
        })
    }
    function* _loadUserInfo () {
        console.log("**********************");
        yield put(UpdateUserAction(res.data));
    }


/// Dart

  var a = 1;

  void doSomeThing() async {
    var result = await xxxx();
    doAsync().then((res) {
      print('ffff');
    });
  }
  _loadUserInfo() async* {
    print("**********************");
    yield UpdateUserAction(res.data);
  }


但是它們之間的差異性也很多碑定,而最大的區(qū)別就是: JS 是動(dòng)態(tài)語(yǔ)言,而 Dart 是偽動(dòng)態(tài)語(yǔ)言的強(qiáng)類(lèi)型語(yǔ)言又官。

如下代碼中延刘,在 Dart 中可以直接聲明 nameString 類(lèi)型,同時(shí) otherName 雖然是通過(guò) var 語(yǔ)法糖聲明六敬,但在賦值時(shí)其實(shí)會(huì)通過(guò)自推導(dǎo)出類(lèi)型 碘赖,而 dynamic 聲明的才是真的動(dòng)態(tài)變量,在運(yùn)行時(shí)才檢測(cè)類(lèi)型。

// Dart

String name = 'dart'; 
var otherName = 'Dart';
dynamic dynamicName = 'dynamic Dart'; 

如下圖代碼最能體現(xiàn)這個(gè)差異普泡,在下圖例子中:

  • var i 在全局中未聲明類(lèi)型時(shí)播掷,會(huì)被指定為 dymanic ,從而導(dǎo)致在 init() 方法中編譯時(shí)不會(huì)判斷類(lèi)型撼班,這和 JS 內(nèi)的現(xiàn)象會(huì)一致歧匈。

  • 如果將 var i = ""; 定義在 init() 方法內(nèi),這時(shí)候 i 已經(jīng)是強(qiáng)類(lèi)型 String了 砰嘁,所以編譯器會(huì)在 i++報(bào)錯(cuò)件炉,但是這個(gè)寫(xiě)法在 JS 動(dòng)態(tài)語(yǔ)言里,默認(rèn)編譯時(shí)是不會(huì)報(bào)錯(cuò)的矮湘。

動(dòng)態(tài)語(yǔ)言和非動(dòng)態(tài)語(yǔ)言都有各種的優(yōu)缺點(diǎn)斟冕,比如 JS 開(kāi)發(fā)便捷度明顯會(huì)高于 Dart ,而 Dart 在類(lèi)型安全和重構(gòu)代碼等方面又會(huì)比 JS 更穩(wěn)健缅阳。

3.2磕蛇、界面開(kāi)發(fā)

React Native 在界面開(kāi)發(fā)上延續(xù)了 React 的開(kāi)發(fā)風(fēng)格,支持 scss/sass 券时、樣式代碼分離孤里、在 0.59 版本開(kāi)始支持 React Hook 函數(shù)式編程 等等,而不同 React 之處就是更換標(biāo)簽名橘洞,并且樣式和屬性支持因?yàn)槠脚_(tái)兼容做了刪減捌袜。

如下圖所示,是一個(gè)普通 React Native 組件常見(jiàn)實(shí)現(xiàn)方式炸枣,繼承 Component 類(lèi)虏等,通過(guò) props 傳遞參數(shù),然后在 render 方法中返回需要的布局适肠,布局中每個(gè)控件通過(guò) style 設(shè)置樣式 等等霍衫,這對(duì)于前端開(kāi)發(fā)者基本上沒(méi)有太大的學(xué)習(xí)成本。

如下所示侯养,如果再配合 React Hooks 的加持敦跌,函數(shù)式的開(kāi)發(fā)無(wú)疑讓整個(gè)代碼結(jié)構(gòu)更為簡(jiǎn)潔。

Flutter 最大的特點(diǎn)在于: Flutter 是一套平臺(tái)無(wú)關(guān)的 UI 框架逛揩,在 Flutter 宇宙中萬(wàn)物皆 Widget柠傍。

如下圖所示,Flutter 開(kāi)發(fā)中一般是通過(guò)繼承 無(wú)狀態(tài) StatelessWidget 控件或者 有狀態(tài) StatefulWidget 控件 來(lái)實(shí)現(xiàn)頁(yè)面辩稽,然后在對(duì)應(yīng)的 Widget build(BuildContext context) 方法內(nèi)實(shí)現(xiàn)布局惧笛,利用不同 Widgetchild / children 去做嵌套,通過(guò)控件的構(gòu)造方法傳遞參數(shù)逞泄,最后對(duì)布局里的每個(gè)控件設(shè)置樣式等患整。

而對(duì)于 Flutter 控件開(kāi)發(fā)拜效,目前最多的吐槽就是 控件嵌套和樣式代碼不分離 ,樣式代碼分離這個(gè)問(wèn)題我就暫不評(píng)價(jià)各谚,這個(gè)真要實(shí)際開(kāi)發(fā)才能更有體會(huì)紧憾,而關(guān)于嵌套這里可以做一些 “洗白” :

Flutter 中把一切皆為 Widget 貫徹得很徹底,所以 Widget 的顆粒度控制得很細(xì) 嘲碧,如 Padding 稻励、Center 都會(huì)是一個(gè)單獨(dú)的 Widget父阻,甚至狀態(tài)共享都是通過(guò) InheritedWidget 共享 Widget 去實(shí)現(xiàn)的愈涩,而這也是被吐槽的代碼嵌套樣式難看的原因。

事實(shí)上正是因?yàn)轭w粒度細(xì)加矛,所以你才可以通過(guò)不同的 Widget 履婉, 自由組合出多種業(yè)務(wù)模版, 比如 Flutter 中常用的 Container 斟览,它就是官方幫你組合好的模板之一毁腿, Container 內(nèi)部其實(shí)是由 AlignConstrainedBox 苛茂、DecoratedBox 已烤、PaddingTransform 等控件組合而成 妓羊,所以嵌套深度等問(wèn)題完全是可以人為控制胯究,甚至可以在幀率和繪制上做到更細(xì)致的控制。

當(dāng)然躁绸,官方也在不斷地改進(jìn)優(yōu)化編寫(xiě)和可視化的體驗(yàn)裕循,如下圖所示,從目前官方放出的消息上看净刮,未來(lái)這個(gè)問(wèn)題也會(huì)被進(jìn)一步改善剥哑。

最后總結(jié)一下,拋開(kāi)上面的開(kāi)發(fā)風(fēng)格淹父,React Native 在 UI 開(kāi)發(fā)上最大的特點(diǎn)就是平臺(tái)相關(guān)株婴,而 Flutter 則是平臺(tái)無(wú)關(guān),比如下拉刷新暑认,在 React Native 中困介, <RefreshControl> 會(huì)自帶平臺(tái)的不同下拉刷新效果穷吮,而在 Flutter 中逻翁,如果需要平臺(tái)不同下拉刷新效果,那么你需要分別使用 RefreshIndicatorCupertinoSliverRefreshControl 做顯示捡鱼,不然多端都會(huì)呈現(xiàn)出一致的效果八回。

3.3、狀態(tài)管理

前面說(shuō)過(guò), Flutter 在很多方面都借鑒了 React Native 缠诅,所以在狀態(tài)管理方面也極具“即視感”溶浴,比如都是調(diào)用 setState 的方式去更新,同時(shí)操作都不是立即生效的 管引,當(dāng)然它們也有著差異的地方士败,如下代碼所示:

  • 正常情況下 React Native 需要在 Component 內(nèi)初始化一個(gè) this.state 變量,然后通過(guò) this.state.name 訪問(wèn) 褥伴。
  • Flutter 繼承 StatefulWidget 谅将,然后在其的 State 對(duì)象內(nèi)通過(guò)變量直接訪問(wèn)和 setState 觸發(fā)更新。
/// JS

    this.state = {
       name: ""
    };
    
    ···
     
    this.setState({
        name: "loading"
    });
    
    ···
    
    <Text>this.state.name</Text>
    
    
/// Dart

    var name = "";

    setState(() {
       name =  "loading";
    });
    
    ···
    
    Text(name)

當(dāng)然它們兩者的內(nèi)部實(shí)現(xiàn)也有著很大差異重慢,比如 React Native 受 React diff 等影響隅熙,而 Flutter 受 isRepaintBoundary 驰坊、markNeedsBuild 等影響借嗽。

而在第三方狀態(tài)管理上浆竭,兩者之間有著極高的相似度顺囊,如早期在 Flutter 平臺(tái)就涌現(xiàn)了很多前端的狀態(tài)管理框架如:flutter_redux 午乓、fish_reduxdva_flutter 枣接、flutter_mobx 等等湿蛔,它們的設(shè)計(jì)思路都極具 React 特色。

同時(shí) Flutter 官方也提供了 scoped_modelprovider 等具備 Flutter 特色的狀態(tài)管理所踊。

所以在狀態(tài)管理上 React Native 和 Flutter 是十分相近的继薛,甚至是在跟著 React 走蓝谨。

3.4、原生控件

在跨平臺(tái)開(kāi)發(fā)中,就不得不說(shuō)到接入原有平臺(tái)的支持宵睦,比如 在 Android 平臺(tái)上接入 x5 瀏覽器 烟馅、接入視頻播放框架捆憎、接入 Lottie 動(dòng)畫(huà)框架等等。

這一需求 React Native 先天就支持瞬沦,甚至在社區(qū)就已經(jīng)提供了類(lèi)似 lottie-react-native 的項(xiàng)目太伊。 因?yàn)?React Native 整個(gè)渲染過(guò)程都在原生層中完成,所以接入原有平臺(tái)控件并不會(huì)是難事 逛钻,同時(shí)因?yàn)榘l(fā)展多年僚焦,雖然各類(lèi)第三方庫(kù)質(zhì)量參差不齊,但是數(shù)量上的優(yōu)勢(shì)還是很明顯的曙痘。

Flutter 在就明顯趨于弱勢(shì)芳悲,甚至官方在開(kāi)始的時(shí)候立肘,連 WebView 都不支持,這其實(shí)涉及到 Flutter 的實(shí)現(xiàn)原理問(wèn)題名扛。

因?yàn)? Flutter 的整體渲染脫離了原生層面谅年,直接和 GPU 交互,導(dǎo)致了原生的控件無(wú)法直接插入其中 肮韧,而在視頻播放實(shí)現(xiàn)上融蹂, Flutter 提供了外界紋理的設(shè)計(jì)去實(shí)現(xiàn),但是這個(gè)過(guò)程需要的數(shù)據(jù)轉(zhuǎn)換弄企,很明顯的限制了它的通用性超燃, 所以在后續(xù)版本中 Flutter 提供了 PlatformView 的模式來(lái)實(shí)現(xiàn)集成。

Android 為例子拘领,在原生層 Flutter 通過(guò) Presentation 副屏顯示的原理意乓,利用 VirtualDisplay 的方式,讓 Android 控件在內(nèi)存中繪制到 Surface 層约素。 VirtualDisplay 繪制在 SurfacetextureId 届良,之后會(huì)通知到 Dart 層,在 Dart 層利用 AndroidView 定義好的 Widget 并帶上 textureId 业汰,那么 Engine 在渲染時(shí)伙窃,就會(huì)在內(nèi)存中將 textureId 對(duì)應(yīng)的數(shù)據(jù)渲染到 AndroidView 上。

PlatformView 的設(shè)計(jì)必定導(dǎo)致了性能上的缺陷样漆,最大的體現(xiàn)就是內(nèi)存占用的上漲,同時(shí)也引導(dǎo)了諸如鍵盤(pán)無(wú)法彈出#19718和黑屏等問(wèn)題晦闰,甚至于在 Android 上的性能還可能不如外界紋理放祟。

所以目前為止, Flutter 原生控件的接入上是仍不如 React Native 穩(wěn)定呻右。

四跪妥、 插件開(kāi)發(fā)

React NativeFlutter 都是支持插件開(kāi)發(fā),不同在于 React Native 開(kāi)發(fā)的是 npm 插件声滥,而 Flutter 開(kāi)發(fā)的是 pub 插件眉撵。

React Native 使用 npm 插件的好處就是:可以使用豐富的 npm 插件生態(tài),同時(shí)減少前端開(kāi)發(fā)者的學(xué)習(xí)成本落塑。

但是使用 npm 的問(wèn)題就是太容易躺坑纽疟,因?yàn)? npm 包依賴(lài)的復(fù)雜度和深度所惑,以至于你都可能不知道 npm 究竟裝了什么東西憾赁,拋開(kāi)安全問(wèn)題污朽,這里最直觀的感受就是 :“為什么別人跑得起來(lái),而我的跑不起來(lái)龙考?” 同時(shí)每個(gè)項(xiàng)目都獨(dú)立一個(gè) node_module 蟆肆,對(duì)于硬盤(pán)空間較小的 Mac 用戶(hù)略顯心酸矾睦。

Flutterpub 插件默認(rèn)統(tǒng)一管理在 pub 上,類(lèi)似于 npm 同樣支持 git 鏈接安裝炎功,而 flutter packages get 文件一般保存在電腦的統(tǒng)一位置枚冗,多個(gè)項(xiàng)目都引用著同一份插件。

  • win 一般是在 C:\Users\xxxxx\AppData\Roaming\Pub\Cache 路徑下
  • mac 目錄在 ~/.pub-cache

如果找不到插件目錄蛇损,也可以通過(guò)查看 .flutter-plugins 文件官紫,或如下圖方式打開(kāi)插件目錄,至于為什么需要打開(kāi)這個(gè)目錄州藕,感興趣的可以看看這個(gè)問(wèn)題 13# 束世。

最后說(shuō)一下 FlutterReact Native 插件,在帶有原生代碼時(shí)不同的處理方法:

  • React Native 在安裝完帶有原生代碼的插件后床玻,需要執(zhí)行 react-native link 腳本去引入支持毁涉,具體如 Android 會(huì)在 setting.gradlebuild.gradleMainApplication.java 等地方進(jìn)行侵入性修改而達(dá)到引用夕玩。

  • Flutter 則是通過(guò) .flutter-plugins 文件剪验,保存了帶有原生代碼的插件 key-value 路徑 ,之后 Flutter 的腳本會(huì)通過(guò)讀取的方式其屏,動(dòng)態(tài)將原生代碼引入,最后通過(guò)生成 GeneratedPluginRegistrant.java 這個(gè)忽略文件完成導(dǎo)入缨该,這個(gè)過(guò)程開(kāi)發(fā)者基本是無(wú)感的偎行。

所以在插件這一塊的體驗(yàn), Flutter 是略微優(yōu)于 React Native 的贰拿。

五蛤袒、 編譯和產(chǎn)物

React Native 編譯后的文件主要是 bundle 文件,在 Android 中是 index.android.bunlde 文件膨更,而在 IOS 下是 main.jsbundle 妙真。

Flutter 編譯后的產(chǎn)物在 Android 主要是 :

  • isolate_snapshot_instr 應(yīng)用程序指令段
  • isolate_snapshot_data應(yīng)用程序數(shù)據(jù)段
  • vm_snapshot_data 虛擬機(jī)數(shù)據(jù)段
  • vm_snapshot_instr 虛擬機(jī)指令段等產(chǎn)物

?注意,1.7.8 之后的版本荚守,Android 下的 Flutter 已經(jīng)編譯為純 so 文件珍德。

在 IOS 主要是 App.framework ,其內(nèi)部也包含了 kDartVmSnapshotData 矗漾、kDartVmSnapshotInstructions 锈候、 kDartIsolateSnapshotDatakDartIsolateSnapshotInstructions 四個(gè)部分缩功。

接著看完整結(jié)果晴及,如下圖所示,是空項(xiàng)目下 和 GSY 實(shí)際項(xiàng)目下嫡锌, React NativeFlutter 的 Release 包大小對(duì)比虑稼。

可以看出在 React Native 同等條件下琳钉,Android 比 IOS 大很多 ,這是因?yàn)?IOS 自帶了 JSCore 蛛倦,而 Android 需要各類(lèi)動(dòng)態(tài) so 內(nèi)置支持歌懒,而且這里 Android 的動(dòng)態(tài)庫(kù) so 是經(jīng)過(guò)了 ndk 過(guò)濾后的大小,不然還會(huì)更大溯壶。

FlutterReact Native 則是相反及皂,因?yàn)?Android 自帶了 skia ,所以比沒(méi)有自帶 skiaIOS 會(huì)小得多且改。

以上的特點(diǎn)在 GSY 項(xiàng)目中的 Release 包也呈同樣狀態(tài)验烧。

類(lèi)型 React Native Flutter
空項(xiàng)目 Android
Rn Android ndk abiFilters arm64-v8a
Flutter Android
空項(xiàng)目 IOS
Rn IOS
Flutter IOS
GSY Android
GSYGIthubApp.apk
GSYGithubAppFlutter.apk
GSY IOS
GSYGithubAPP.ipa
GSYGithubAppFlutter.ipa

值得注意的是,Google Play 最近發(fā)布了 《8月不支持 64 位又跛,App 將無(wú)法上架 Google Play碍拆!》 的通知 ,同時(shí)也表示將停止 Android Studio 32 位的維護(hù)慨蓝,而 arm64-v8a 格式的支持感混,React Native 需要在 0.59 以后的版本才支持。

至于 Flutter 礼烈,在打包時(shí)通過(guò)指定 flutter build apk --release --target-platform android-arm64 即可弧满。

六、性能

說(shuō)到性能此熬,這是一個(gè)大家都比較關(guān)心的概念庭呜,但是有一點(diǎn)需要注意,拋開(kāi)場(chǎng)景說(shuō)性能顯然是不合適的摹迷,因?yàn)樾阅芎痛a質(zhì)量與復(fù)雜度是有一定聯(lián)系的疟赊。

先說(shuō)理論性能,**在理論上 Flutter 的設(shè)計(jì)性能是強(qiáng)于 React Native ** 峡碉,這是框架設(shè)計(jì)的理念導(dǎo)致的,F(xiàn)lutter 在少了 OEM Widget 驮审,直接與 CPU / GPU 交互的特性鲫寄,決定了它先天性能的優(yōu)勢(shì)。

這里注意不要用模擬器測(cè)試性能疯淫,特別是IOS模擬器做性能測(cè)試地来,因?yàn)?Flutter 在 IOS模擬器中純 CPU ,而實(shí)際設(shè)備會(huì)是 GPU 硬件加速熙掺,同時(shí)只在 Release 下對(duì)比性能未斑。

代碼的實(shí)現(xiàn)方式不同,也可能會(huì)導(dǎo)致性能的損失币绩,比如 Flutterskia 在繪制時(shí)蜡秽,saveLayer 是比較消耗性能的府阀,比如 透明合成、clipRRect 等等芽突,都會(huì)可能需要 saveLayer 的調(diào)用试浙, 而 saveLayer 會(huì)清空GPU繪制的緩存,導(dǎo)致性能上的損耗寞蚌,從而導(dǎo)致開(kāi)發(fā)過(guò)程中如果掉幀嚴(yán)重田巴。

最后如下圖所示,是去年閑魚(yú)用 GSY 項(xiàng)目做測(cè)試對(duì)比的數(shù)據(jù)挟秤,原文在《流言終結(jié)者- Flutter和RN誰(shuí)才是更好的跨端開(kāi)發(fā)方案壹哺?》 ,可以看出在去年的時(shí)候艘刚, Flutter的整體幀率和繪制就有了明顯的優(yōu)勢(shì)管宵。

額外補(bǔ)充一點(diǎn),JSDart 都是單線程應(yīng)用昔脯,利用了協(xié)程的概念實(shí)現(xiàn)異步效果啄糙,而在 FlutterDart 支持的 isolate ,卻是屬于完完全全的異步線程處理云稚,可以通過(guò) Port 快捷地進(jìn)行異步交互隧饼,這大大拓展了 FlutterDart 層面的性能優(yōu)勢(shì)。

七静陈、發(fā)展未來(lái)

之前一篇 《為什么 Airbnb 放棄了 React Native?》 文章燕雁,讓眾多不明所以的吃瓜群眾以為 React Native 已經(jīng)被放棄,之后官方發(fā)布的
《Facebook 正在重構(gòu) React Native鲸拥,將重寫(xiě)大量底層》 公示拐格,又再一次穩(wěn)定了軍心。

同時(shí) React Native 在 0.59 版本開(kāi)始支持 React Hook 等特性刑赶,并將原本平臺(tái)的特性控件從 React Native 內(nèi)部剝離到社區(qū)捏浊,這樣控件的單獨(dú)升級(jí)維護(hù)可以更加便捷,同時(shí)讓 React NativeReact 之間的界限越發(fā)模糊撞叨。

Flutter UI 平臺(tái)的無(wú)關(guān)能力金踪,讓 Flutter 在跨平臺(tái)的拓展上更為迅速,盡管 React Native 也有 WebPC 等第三方實(shí)現(xiàn)拓展支持牵敷,但是由于平臺(tái)關(guān)聯(lián)性太強(qiáng)胡岔,這些年發(fā)展較為緩慢, 而 Flutter 則是短短時(shí)間又宣布 Web 支持枷餐,甚至拓展到 PC 和嵌入式設(shè)備當(dāng)中靶瘸。

這里面對(duì)于 Flutter For Web 相信是大家最為關(guān)心的話題, 如下圖所示,在 Flutter 的設(shè)計(jì)邏輯下怨咪,開(kāi)發(fā) Flutter Web 的過(guò)程中屋剑,你甚至感知不出來(lái)你在開(kāi)發(fā)的是 Web 應(yīng)用。

Flutter Web 保留了 大量原本已有的移動(dòng)端邏輯惊暴,只是在 Engine 層利用 Dart2Js 的能力實(shí)現(xiàn)了差異化饼丘, 不過(guò)現(xiàn)階段而言,F(xiàn)lutter Web 仍處在技術(shù)預(yù)覽階段辽话,不建議在生產(chǎn)環(huán)境中使用 肄鸽。

由此可以推測(cè),不管是 Flutter 或者 React Native油啤,都會(huì)努力將自己拓展到更多的平臺(tái)典徘,同時(shí)在自己的領(lǐng)域內(nèi)進(jìn)一步簡(jiǎn)化開(kāi)發(fā)。

  • 其他參考資料 :

《Facebook 正在重構(gòu) React Native益咬,將重寫(xiě)大量底層》

《React Native 的未來(lái)與React Hooks》

《庖丁解牛逮诲!深入剖析 React Native 下一代架構(gòu)重構(gòu)》

《Flutter 最新進(jìn)展與未來(lái)展望》

自此,本文終于結(jié)束了幽告,長(zhǎng)呼一口氣梅鹦。

資源推薦

文章

《Flutter完整開(kāi)發(fā)實(shí)戰(zhàn)詳解系列》
《移動(dòng)端跨平臺(tái)開(kāi)發(fā)的深度解析》

GSYTech
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冗锁,隨后出現(xiàn)的幾起案子齐唆,更是在濱河造成了極大的恐慌,老刑警劉巖冻河,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箍邮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡叨叙,警方通過(guò)查閱死者的電腦和手機(jī)锭弊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)擂错,“玉大人味滞,你說(shuō)我怎么就攤上這事∨パ剑” “怎么了桃犬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)行楞。 經(jīng)常有香客問(wèn)我,道長(zhǎng)土匀,這世上最難降的妖魔是什么子房? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上证杭,老公的妹妹穿的比我還像新娘田度。我一直安慰自己,他們只是感情好解愤,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布镇饺。 她就那樣靜靜地躺著,像睡著了一般送讲。 火紅的嫁衣襯著肌膚如雪奸笤。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天哼鬓,我揣著相機(jī)與錄音监右,去河邊找鬼。 笑死异希,一個(gè)胖子當(dāng)著我的面吹牛健盒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播称簿,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼扣癣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了憨降?” 一聲冷哼從身側(cè)響起父虑,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎券册,沒(méi)想到半個(gè)月后频轿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烁焙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年航邢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骄蝇。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膳殷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出九火,到底是詐尸還是另有隱情赚窃,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布岔激,位于F島的核電站勒极,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏虑鼎。R本人自食惡果不足惜辱匿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一键痛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匾七,春花似錦絮短、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至邑贴,卻和暖如春席里,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痢缎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工胁勺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人独旷。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓署穗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嵌洼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子案疲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容