作為 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 Native 和 Flutter 進(jìn)行全面的分析對(duì)比,希望能給你更有價(jià)值的參考惩系。
是的位岔,這次沒(méi)有了 Weex,超長(zhǎng)內(nèi)容預(yù)警堡牡,建議收藏后閱抒抬。
前言
臨冬之際,移動(dòng)端跨平臺(tái)在經(jīng)歷數(shù)年沉浮之后晤柄,如今還能在舞臺(tái)聚光燈下雀躍的擦剑, 也只剩下 React Native 和 Flutter 了,作為沉淀了數(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ù)者 | ||
風(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 ,都需要 Android 和 IOS 的開(kāi)發(fā)環(huán)境安吁,也就是 JDK 醉蚁、Android SDK、Xcode 等環(huán)境配置鬼店,而不同點(diǎn)在于 :
-
React Native 需要
npm
网棍、node
、react-native-cli
等配置 妇智。 -
Flutter 需要
flutter sdk
和 Android Studio / VSCode 上的 Dart 與 Flutter 插件滥玷。
從配置環(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)原理
在 Android 和 IOS 上夭禽,默認(rèn)情況下 Flutter 和 React 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 而生,所以 Dart 和 JS 在一定程度上有很大的通識(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
中可以直接聲明 name
為 String
類(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)布局惧笛,利用不同 Widget
的 child
/ 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í)是由 Align
、 ConstrainedBox
苛茂、DecoratedBox
已烤、Padding
、Transform
等控件組合而成 妓羊,所以嵌套深度等問(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)不同下拉刷新效果,那么你需要分別使用 RefreshIndicator
和 CupertinoSliverRefreshControl
做顯示捡鱼,不然多端都會(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_redux 、 dva_flutter 枣接、flutter_mobx 等等湿蛔,它們的設(shè)計(jì)思路都極具 React 特色。
同時(shí) Flutter 官方也提供了 scoped_model 、provider 等具備 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
繪制在Surface
的 textureId 届良,之后會(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 Native 和 Flutter 都是支持插件開(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ù)略顯心酸矾睦。
Flutter 的 pub 插件默認(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ō)一下 Flutter 和 React Native 插件,在帶有原生代碼時(shí)不同的處理方法:
React Native 在安裝完帶有原生代碼的插件后床玻,需要執(zhí)行
react-native link
腳本去引入支持毁涉,具體如 Android 會(huì)在setting.gradle
、build.gradle
、MainApplication.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
锈候、 kDartIsolateSnapshotData
、kDartIsolateSnapshotInstructions
四個(gè)部分缩功。
接著看完整結(jié)果晴及,如下圖所示,是空項(xiàng)目下 和 GSY 實(shí)際項(xiàng)目下嫡锌, React Native 和 Flutter 的 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ì)更大溯壶。
Flutter 和 React Native 則是相反及皂,因?yàn)?Android 自帶了 skia ,所以比沒(méi)有自帶 skia 的 IOS 會(huì)小得多且改。
以上的特點(diǎn)在 GSY 項(xiàng)目中的 Release 包也呈同樣狀態(tài)验烧。
類(lèi)型 | React Native | Flutter |
---|---|---|
空項(xiàng)目 Android | ||
空項(xiàng)目 IOS | ||
GSY Android | ||
GSY IOS |
值得注意的是,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)致性能的損失币绩,比如 Flutter 中 skia 在繪制時(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),JS 和 Dart 都是單線程應(yīng)用昔脯,利用了協(xié)程的概念實(shí)現(xiàn)異步效果啄糙,而在 Flutter 中 Dart 支持的
isolate
,卻是屬于完完全全的異步線程處理云稚,可以通過(guò) Port 快捷地進(jìn)行異步交互隧饼,這大大拓展了 Flutter 在 Dart 層面的性能優(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 Native 與 React 之間的界限越發(fā)模糊撞叨。
Flutter UI 平臺(tái)的無(wú)關(guān)能力金踪,讓 Flutter 在跨平臺(tái)的拓展上更為迅速,盡管 React Native 也有 Web 和 PC 等第三方實(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)》
自此,本文終于結(jié)束了幽告,長(zhǎng)呼一口氣梅鹦。
資源推薦
- Github : https://github.com/CarGuo
- 開(kāi)源 Flutter 項(xiàng)目:https://github.com/CarGuo/GSYGithubAppFlutter
- 開(kāi)源 React Native 項(xiàng)目:https://github.com/CarGuo/GSYGithubApp
- 開(kāi)源 Fluttre 實(shí)戰(zhàn)電子書(shū)項(xiàng)目:https://github.com/CarGuo/GSYFlutterBook
文章
《Flutter完整開(kāi)發(fā)實(shí)戰(zhàn)詳解系列》
《移動(dòng)端跨平臺(tái)開(kāi)發(fā)的深度解析》