大家好坠七,我是郭樹煜毒嫡,Github GSY 系列開源項(xiàng)目的作者莹妒,系列包括有 GSYVideoPlayer 、GSYGitGithubApp(Flutter\ReactNative\Kotlin\Weex)四大版本诈茧,目前總 star 在 17
k+ 左右,主要活躍在掘金社區(qū)捂掰,id 是戀貓的小郭敢会,主要專欄有《Flutter完整開發(fā)實(shí)戰(zhàn)詳解》系列等,平時(shí)工作負(fù)責(zé)移動(dòng)端項(xiàng)目的開發(fā)这嚣,工作經(jīng)歷從 Android 到 React Native 鸥昏、Weex 再到如今的 Flutter ,期間也參與過(guò) React 疤苹、 Vue 互广、小程序等相關(guān)的開發(fā),算是一個(gè)大前端的選手吧。
這次主要是給大家分享 Flutter 相關(guān)的內(nèi)容惫皱,主要涉及做一些實(shí)戰(zhàn)和科普性質(zhì)的內(nèi)容像樊。
一、移動(dòng)開發(fā)的現(xiàn)狀
恰逢最近谷歌 IO 大會(huì)結(jié)束旅敷,大會(huì)后也在線上線下和大家有過(guò)交流生棍,總結(jié)了下大家最關(guān)系的問(wèn)題有:
1、谷歌在 Kotlin-First 的口號(hào)下又推廣 Dart + Flutter 沖突嗎媳谁?
這個(gè)問(wèn)題算是被問(wèn)得最多的一個(gè)涂滴,先說(shuō)觀點(diǎn):我個(gè)人認(rèn)為其實(shí)這并不沖突,因?yàn)橛袀€(gè) 誤區(qū)就是認(rèn)為跨平臺(tái)開發(fā)就可以拋棄原生開發(fā)晴音!
如果從事過(guò)跨平臺(tái)開發(fā)的同學(xué)應(yīng)該知道柔纵,平臺(tái)提供的功能向來(lái)是有限的,而面對(duì)產(chǎn)品經(jīng)理的各種 “點(diǎn)歪技能樹” 的需求锤躁,很多時(shí)候你是需要基于框架外提供支持搁料,常見的就是 混合開發(fā)或者原生插件支持 。
所以這里我表達(dá)的是系羞,目前 Kotlin
和 Dart
更多是相輔相成 郭计,而一旦業(yè)務(wù)復(fù)雜度到一定程度,跨平臺(tái)框架還可能存在降低工作效率的問(wèn)題椒振,比如針對(duì)新需求昭伸,需要重復(fù)開發(fā) Android/IOS
的原生插件做支持,這也是 Aribnb 曾經(jīng)選擇放棄 React Native
的原因之一澎迎。
與我而言庐杨,跨平臺(tái)的意義在于解決的是端邏輯的統(tǒng)一 ,至少避免了邏輯重復(fù)實(shí)現(xiàn)嗡善,或者 IOS
和 Android
之間爭(zhēng)論 誰(shuí)對(duì)誰(shuí)錯(cuò) 的問(wèn)題辑莫,甚至可以統(tǒng)一到 web 端等等。
2罩引、React Native 和 Flutter 之間的對(duì)比
Flutter
作為后來(lái)者各吨,難免會(huì)被用來(lái)和 React Native
進(jìn)行對(duì)比,在這個(gè)萬(wàn)物皆是 JS
的時(shí)代袁铐,Dart
和 Flutter
的出現(xiàn)顯得尤為扎眼揭蜒。
在設(shè)計(jì)上它們有著許多相似之處,響應(yīng)式設(shè)計(jì)/async支持/setState更新 等等剔桨,同時(shí)也有著各種的差異屉更,而大家最為關(guān)心的,無(wú)非 性能洒缀、支持瑰谜、上手難易欺冀、穩(wěn)定性程度 這四方面:
-
性能上 Flutter 的確實(shí)會(huì)比 React Native 好 ,如下圖所示萨脑,這是由框架底層決定的隐轩,當(dāng)然目前
React Native
也在進(jìn)行下一代的優(yōu)化, 而對(duì)此最直觀的數(shù)據(jù)就是:GSY系列 在18年用于閑魚測(cè)試下的對(duì)比數(shù)據(jù)了 渤早。
同時(shí)注意不要用模擬器測(cè)試性能职车,特別是IOS模擬器做性能測(cè)試,因?yàn)?Flutter 在 IOS模擬器中純 CPU 鹊杖,而實(shí)際設(shè)備會(huì)是 GPU 硬件加速悴灵,同時(shí)只在 Release 下對(duì)比性能。
支持上 Flutter 和 React Native 骂蓖, 都存在第三方包質(zhì)量參差不齊的問(wèn)題积瞒,而目前在這一塊 Flutter 是弱于 React Native 的 ,畢竟
React Native
發(fā)展已久登下,雖然版本號(hào)一直不到 1.0赡鲜,但是在JS
的加持下生態(tài)豐富,同時(shí)也是因?yàn)槠脚_(tái)特性的原因庐船,諸如 WebView 、地圖等控件的支持上現(xiàn)在依舊不夠好嘲更,這個(gè)后面也會(huì)說(shuō)道筐钟。上手難易度上,
Flutter
配置環(huán)境和運(yùn)行的“成功率”比 React Native 高不少 赋朦,這里面有node_module
黑洞這個(gè)坑篓冲,也有React Native
本身依賴平臺(tái)控件導(dǎo)致的,至少我曾經(jīng)試過(guò)接手一個(gè)React Native
跑了一天都沒跑起來(lái)的經(jīng)歷宠哄,同時(shí)Flutter
在運(yùn)行和SDK版本升級(jí)的陣痛也會(huì)少很多壹将。穩(wěn)定性:
Flutter
中大部分異常是不會(huì)引起應(yīng)用崩潰 ,更多會(huì)在 Debug 上體現(xiàn)為紅色錯(cuò)誤堆棧毛嫉,Release 上 UI 異常等等诽俯。
如果你是前端,我會(huì)推薦你先學(xué)
React Native
承粤,如果你是原生開發(fā)暴区,我推薦你學(xué)Flutter
鹊奖。在 React Native 0.59.x 版本開始偏形,React 已經(jīng)將許多內(nèi)置控件和庫(kù)移出主項(xiàng)目,希望模糊 React 和 React Native 的界線帜篇,統(tǒng)一開發(fā)彻舰,這里的理念和 Flutter 很像伐割。
Flutter 暫時(shí)不支持熱更新:蛭丁!8粜摹0兹骸!<醚住4铡!
二须尚、Flutter 實(shí)戰(zhàn)
1崖堤、Dart 中有意思的一些東西
1.1、var 的語(yǔ)法糖和 dynamic
var
的語(yǔ)法糖是在賦值時(shí)才自推導(dǎo)出類型的 耐床,而 dynamic
是動(dòng)態(tài)聲明密幔,在運(yùn)行時(shí)檢測(cè),它們的使用有時(shí)候容易出現(xiàn)錯(cuò)誤撩轰。
如下圖所以說(shuō)胯甩,
-
var
初始化時(shí)被指定為dynamic
類型的。 - 然后賦值的時(shí)候初始化為
String
類型堪嫂,這時(shí)候進(jìn)行 ++ 操作就會(huì)出現(xiàn)運(yùn)行時(shí)報(bào)錯(cuò)偎箫, - 如下圖2如果在初始化指定類型的,那么編譯時(shí)就會(huì)告訴你錯(cuò)誤了皆串。
1.2淹办、各類操作符
如下圖所示,Dart
支持很多有意思的操作符恶复,如下圖:
- 執(zhí)行的時(shí)候首先是判斷
AA
如果為空怜森,就返回999
; - 之后如果
AA
為空谤牡,就為AA
賦值999
副硅; - 之后對(duì)
AA
進(jìn)行整除999
,輸出結(jié)果10
翅萤。
1.3恐疲、支持操作符重載
如下圖所示,Dart
中是支持操作符重載的套么,這樣可以比較直觀我們的代碼邏輯流纹,并且簡(jiǎn)化代碼時(shí)的調(diào)用。
1.4违诗、方法當(dāng)做參數(shù)傳遞
如下圖所示漱凝,在 Dart
中方法時(shí)可以作為參數(shù)傳遞的,這樣的形式可以讓我們更靈活的組織代碼的邏輯诸迟。
1.5茸炒、async await / async* yield
在 Dart
中 async await / async* yield
等語(yǔ)法糖愕乎,代表 Dart
中的 Future
和 Stream
操作,它們對(duì)應(yīng) Dart
中的異步邏輯支持壁公。
sync* / yield 對(duì)應(yīng)
Stream
的同步操作感论。
1.6、Mixins
在 Dart
中支持混入的模式紊册,如下圖所示比肄,混入時(shí)的基礎(chǔ)順序是從右到左依次執(zhí)行的,而且和 super
有關(guān)囊陡,同時(shí) Dart
還支持 mixin
關(guān)鍵字的定義芳绩。
Flutter 的啟動(dòng)類用的就是 mixins 方式
1.7、isolate
Dart
中單線程模式中增加了 isolate
提供跨線程的真異步操作撞反,而因?yàn)?Dart
中線程不會(huì)共享內(nèi)存妥色,所以也不存在死鎖,從而也導(dǎo)致了 isolate
之間數(shù)據(jù)只能通過(guò) port
的端口方式發(fā)送接口遏片,類似于 Scoket
的方式嘹害,同時(shí)提供了 compute
的封裝接口方便調(diào)用。
1.8 call
Dart 為了讓類可以像函數(shù)一樣調(diào)用吮便,默認(rèn)都可以實(shí)現(xiàn) call()
方法笔呀,同樣 typedef
定義的方法也是具備 call()
條件。
比如我定義了一個(gè) CallObject
class CallObject {
List<Widget> footerButton = [];
call(int i, double e) => "$i xxxx $e";
}
就可以通過(guò)以下執(zhí)行
CallObject callObject = CallObject();
print(callObject(11, 11.0));
print(callObject?.call(11, 11.0));
然后我定義了
typedef void ValueFunction(int i);
ValueFunction vt = (int i){
print("zzz $i");
};
就可以通過(guò)直接執(zhí)行和判空?qǐng)?zhí)行處理
vt(666);
vt?.call(777);
2髓需、Flutter 中常見的
2.1凿可、ChangeNotifier
如下圖所示,ChangeNotifier
模式在 Flutter
中是十分常見的授账,比如 TextField
控件中,通過(guò) TextEditingController
可以快速設(shè)置值的顯示惨驶,這是為什么呢白热?
如下圖所示,這是因?yàn)?TextEditingController
它是 ChangeNotifier
的子類粗卜,而 TextField
的內(nèi)部對(duì)其進(jìn)行了 addListener
屋确,同時(shí)我們改變值的時(shí)候調(diào)用了notifyListener
,觸發(fā)內(nèi)部 setState
续扔。
2.2攻臀、InheritedWidget
在 Flutter
中所有的狀態(tài)共享都是通過(guò)它實(shí)現(xiàn)的,如自帶的 Theme
纱昧,Localizations
刨啸,或者狀態(tài)管理的 scoope_model
、 flutter_redux
等等识脆,都是基于它實(shí)現(xiàn)的设联。
如下圖是 SliderTheme
的自定義實(shí)現(xiàn)邏輯善已,默認(rèn) Theme
中是包含了 SliderTheme
,但是我們可以通過(guò)覆蓋一個(gè)新的 SliderTheme
嵌套去實(shí)現(xiàn)自定義离例,然后通過(guò) SliderTheme theme = SliderTheme(context);
獲取换团,其中而 context
的實(shí)現(xiàn)就是 Element
。
在 Element
的 inheritFromWidgetOfExactType
方法實(shí)現(xiàn)里宫蛆,有一個(gè) Map<Type, InheritedElement> _inheritedWidgets
的對(duì)象艘包。
_inheritedWidgets
一般情況下是空的,只有當(dāng)父控件是 InheritedWidget
或者本身是 InheritedWidgets
時(shí)才會(huì)有被初始化耀盗,而當(dāng)父控件是 InheritedWidget
時(shí)想虎,這個(gè) Map
會(huì)被一級(jí)一級(jí)往下傳遞與合并 。
所以當(dāng)我們通過(guò) context
調(diào)用 inheritFromWidgetOfExactType
時(shí)袍冷,就可以往上查找到父控件的 Widget
磷醋。
2.3、StreamBuilder
StreamBuilder
一般用于通過(guò) Stream
異步構(gòu)建頁(yè)面的胡诗,如下圖所示邓线,通過(guò)點(diǎn)擊之后,綠色方框的文字會(huì)變成 addNewxxx
煌恢,因?yàn)?Stream
進(jìn)行了 map
變化骇陈,同時(shí)一般實(shí)現(xiàn) bloc
模式的時(shí)候,經(jīng)常會(huì)用到它們瑰抵。
類似的還有 FutureBuilder
2.4你雌、State 中的參數(shù)使用
一般 Widget
都是一幀的,而 State
實(shí)現(xiàn)了 Widget
的跨幀繪制二汛,一般定義的時(shí)候婿崭,我們可以如下圖一樣實(shí)現(xiàn),而如下圖尖頭所示肴颊,這時(shí)候我們點(diǎn)擊 setState
改變的時(shí)候氓栈,是不會(huì)出現(xiàn)效果的,為什么呢婿着?
其實(shí) State 對(duì)象的創(chuàng)建和更新時(shí)機(jī)導(dǎo)致的:
1授瘦、createState 只在 StatefulElement 創(chuàng)建時(shí)才會(huì)被創(chuàng)建的。
2竟宋、StatefulElement 的 createElement 一般只在 inflateWidget 調(diào)用提完。
3、updateChild 執(zhí)行 inflateWidget 時(shí)丘侠, 如果 child 存在可以更新的話徒欣,不會(huì)執(zhí)行 inflateWidget。
3蜗字、四棵樹
Flutter 中主要有
Widget
帚称、Element
官研、RenderObject
、Layer
四棵樹闯睹,它們的作用是:
Widget
:就是我們平常寫的控件戏羽,Flutter
宇宙中萬(wàn)物皆Widget
,它們都是不可變一幀楼吃,同時(shí)也是被人吐槽很多的嵌套模式始花,當(dāng)然換個(gè)角度,事實(shí)上你把他當(dāng)作Widget
配置文件來(lái)寫或者就好理解了孩锡。Element
:它是BuildContext
的實(shí)現(xiàn)類酷宵,Widget
實(shí)現(xiàn)跨幀保存的state
就是存放在這里,同時(shí)它也充當(dāng)了Widget
和RenderObject
之間的橋梁躬窜。RenderObject
:它才是真正干活(layout浇垦、paint)等,同時(shí)它才是真實(shí)的 “dom” 荣挨。Layer
:一整塊的重繪區(qū)域(isRepaintBoundary)男韧,決定重繪的影響區(qū)域。
skia
在繪制的時(shí)候默垄,saveLayer
是比較消耗性能的此虑,比如透明合成、clipRRect
等等都會(huì)可能需要saveLayer
的調(diào)用口锭, 而saveLayer
會(huì)清空GPU繪制的緩存朦前,導(dǎo)致性能上的損耗,所以開發(fā)過(guò)程中如果掉幀嚴(yán)重鹃操,可以針對(duì)這一塊進(jìn)行優(yōu)化韭寸。
4、手勢(shì)
Flutter
在手勢(shì)中引入了競(jìng)技的概念, Down
事件在 Flutter
中尤為重要荆隘。
PointerDownEvent
是一切的起源恩伺,在Down
事件中一般不會(huì)決出勝利者。在
MOVE
和UP
的時(shí)候才競(jìng)爭(zhēng)得到響應(yīng)臭胜。以點(diǎn)擊為例子:
Down
時(shí)添加進(jìn)去參與競(jìng)爭(zhēng),UP
的時(shí)候才決定誰(shuí)勝利癞尚,勝利條件是:
I耸三、UP
的時(shí)候如果只有一個(gè),那么就是它了浇揩。
II仪壮、UP
的時(shí)候如果有多個(gè),那么強(qiáng)制隊(duì)列里第一個(gè)直接勝利胳徽。
- 這里包含了有趣的點(diǎn)就是积锅,都在
UP
的時(shí)候才響應(yīng)爽彤,那么 Down 事件怎么先傳遞出去了?
FLutter
在這里做了一個(gè) didExceedDeadline
機(jī)制 缚陷,事實(shí)上在上面的 addPointer
的時(shí)候适篙,會(huì)啟動(dòng)了一個(gè)定時(shí)器,默認(rèn) 100 ms箫爷,如果超過(guò)指定時(shí)間沒 UP
嚷节,那就先執(zhí)行這個(gè) didExceedDeadline
響應(yīng) Down
事件。
- 那問(wèn)題又來(lái)了虎锚,如果這時(shí)候隊(duì)列里兩個(gè)呢?
它們的 onTapDown
都會(huì)被觸發(fā)硫痰,但是 onTap
只有一個(gè)獲得。
- 如果有兩個(gè)滑動(dòng)
ScrollView
嵌套呢窜护?
舉個(gè)簡(jiǎn)單的例子效斑,兩個(gè) SingleChildScrollView
的嵌套時(shí),在布局會(huì)經(jīng)歷:
performLayout
->applyContentDimensions
->applyNewDimensions
->context.setCanDrag(physics.shouldAcceptUserOffset(this));
只有 shouldAcceptUserOffset
為 ture
時(shí)柱徙,才會(huì)添加 VerticalDragGestureRecognizer
去處理手勢(shì)缓屠。
而判斷條件主要是 return math.max(0.0, child.size.height - size.height);
,也就是如果 child Scroll 的 height 小于父控件 Scroll 的時(shí)候坐搔,就會(huì)出現(xiàn) child 不添加 VerticalDragGestureRecognizer 的情況藏研,這時(shí)候根本就沒有競(jìng)爭(zhēng)了。
5概行、動(dòng)畫
Flutter
中的動(dòng)畫是怎么執(zhí)行的呢蠢挡?
我們先看一段代碼,然后這段代碼執(zhí)行的效果如下圖2所示凳忙。
那既然 Widget
都是一幀业踏,那么動(dòng)畫肯定有 setState
的地方了。
首先這里有個(gè)地方可以看下涧卵,這時(shí)候 200 這個(gè)數(shù)值執(zhí)行后是會(huì)報(bào)錯(cuò)的勤家,因?yàn)榘卓騼?nèi)可見 Tween
中的 T
在這時(shí)候會(huì)出現(xiàn)既有 int
又有 double
,無(wú)法判斷的問(wèn)題柳恐,所以真實(shí)應(yīng)該是 200.0 伐脖。
同時(shí)你發(fā)現(xiàn)沒有,代碼中 parent
的 Container
在 只有100的情況下乐设,它的 child
可以正常的畫 200讼庇,這是因?yàn)槲覀兊?paint
沒有跟著 RenerObjcet
的大小走, 所以一般情況下近尚,整個(gè)屏幕都是我們的畫版蠕啄,Canvas 繪制與父控件大小可以沒關(guān)系。
同時(shí)動(dòng)畫是通過(guò) vsync
同步信號(hào)去觸發(fā)的,就是我們 mixin 的 SingleTickerProviderStateMixin
歼跟,它內(nèi)部的 Ticker
會(huì)通過(guò) SchedulerBinding
的 scheduleFrameCallback
同步信號(hào)觸發(fā)重繪 和媳。
動(dòng)畫后的控件的點(diǎn)擊區(qū)域,和你的動(dòng)畫數(shù)據(jù)改變的是 paint 還是 layout 有關(guān) 哈街。
6留瞳、狀態(tài)管理
scope_model
、flutter_redux
叹卷、fish_redux
撼港、甚至還有有 dva_flutter
等等,可以看出狀態(tài)管理在 flutter
中和前端十分相近骤竹。
這里簡(jiǎn)單說(shuō)說(shuō) scope_model
帝牡,它只有一個(gè)文件,但是很巧妙蒙揣,它利用的就是 AnimationBuilder
的特性靶溜。
如下圖是使用代碼,在前面我們知道懒震,狀態(tài)管理使用的是 InheritedWidget
實(shí)現(xiàn)共享的罩息,而當(dāng)我們對(duì) Model
進(jìn)行數(shù)據(jù)改變時(shí),通過(guò)調(diào)用 notifyListeners
通知頁(yè)面更新了个扰。
這里的原理是什么呢瓷炮?
其實(shí)
scope_model
內(nèi)部利用了AnimationBuilder
,而Model
實(shí)現(xiàn)了Listenable
接口递宅。當(dāng)
Model
設(shè)置給了AnimationBuilder
時(shí)娘香,AnimationBuilder
會(huì)執(zhí)行addListener
添加監(jiān)聽,而監(jiān)聽方法里會(huì)執(zhí)行setState
办龄。所以我們改變
set
方法時(shí)調(diào)用notifyListeners
就觸發(fā)了setState
去更新了烘绽,這樣體現(xiàn)出了前面說(shuō)的FLutter
常見的開發(fā)模式。
三俐填、混合開發(fā)
以 Android
的角度來(lái)說(shuō)安接,從方便調(diào)試和解耦集成上,我們一般會(huì)以 aar
的形式集成混合開發(fā)英融,這里就會(huì)涉及到 gradle
打包的一個(gè)概念盏檐。
1、如下代碼所示驶悟,在項(xiàng)目中進(jìn)行 gradle
腳本修改胡野,組件化開發(fā)模式,用 apk
開發(fā)撩银,用 aar
提供集成给涕,正常修改 gradle
代碼即可快速打包豺憔。
那如果 Flutter
的項(xiàng)目插件帶有本地代碼呢额获?
如果開發(fā)過(guò)
React Native
的應(yīng)該知道够庙,在原生插件安裝時(shí)會(huì)需要執(zhí)行react-native link
,而這時(shí)候會(huì)修改項(xiàng)目的gradle 和java代碼抄邀。
2耘眨、 和 React Native
很有侵入性相比, Flutter
就很巧妙了境肾。
如下圖所示剔难,安裝過(guò)的插件會(huì)出現(xiàn)在 .flutter_plugins
文件中,然后通過(guò)讀取文件奥喻,動(dòng)態(tài)在 setting.gradle
和 flutter.gradle
中引入和依賴:
所以這時(shí)候我們可以參考打包偶宫,修改我們的gradle腳本,利用 fat-aar 插件將本地 projcet 也打包的 aar 里环鲤。
3纯趋、混合開發(fā)的最大痛點(diǎn)是什么?
肯定是堆棧管理!!! 所以項(xiàng)目開發(fā)了 flutter_boost
來(lái)解決這個(gè)問(wèn)題冷离。
- 堆棧統(tǒng)一到了原生層吵冒。
- 通過(guò)一個(gè)唯一
engine
,切換Surface
渲染顯示西剥。 - 每個(gè)
Activity
就是一個(gè)Surface
痹栖,不渲染的頁(yè)面通過(guò)截圖緩存畫面。
flutter_boost
截止到我測(cè)試的時(shí)間 2019-05-16, 只支持 1.2之前的版本
四瞭空、PlatformView
混合開發(fā)除了集成到原生工程揪阿,也有將原生控件集成到 Flutter 渲染樹里里的需求。
首先我們看看沒有 PlatformView
之前是如何實(shí)現(xiàn) WebView
的匙铡,這樣會(huì)有什么問(wèn)題图甜?
如下圖所示,事實(shí)上 dart 中僅僅是用了一個(gè) SingleChildRenderObjectWidget
用于占位鳖眼,將大小傳遞給原生代碼黑毅,然后在原生代碼里顯示出來(lái)而已。
這樣的時(shí)候必定會(huì)代碼畫面堆棧問(wèn)題钦讳,因?yàn)檫@個(gè)顯示脫離了 Flutter 的渲染樹矿瘦,通過(guò)出現(xiàn)動(dòng)畫肯定會(huì)不一致。
4.1 AndroidView
AndroidView -> TextureLayer愿卒,利用Android 上的副屏顯示與虛擬內(nèi)存顯示原理缚去。
共享內(nèi)存,實(shí)時(shí)截圖渲染技術(shù)琼开。
存在問(wèn)題易结,耗費(fèi)內(nèi)存,頁(yè)面復(fù)雜時(shí)慢。
這部分因?yàn)橹耙郧傲倪^(guò)搞动,就不贅述了
三躏精、Flutter Web
RN因?yàn)槭窃丶栽趓eact 和react native 整合這件事上存在難度鹦肿。
flutter 作為一個(gè)UI 框架矗烛,與平臺(tái)無(wú)關(guān),在web上利用的是dart2js的能力箩溃。 比如Image
- 因?yàn)?Flutter 是一套 UI 框架瞭吃,整體 UI 幾乎和平臺(tái)無(wú)關(guān),這和 React Native 有很大的區(qū)別涣旨。(我在開發(fā)過(guò)程中幾乎無(wú)知覺)
- 在 flutter_web 中 UI 層面與渲染邏輯和 Flutter 幾乎沒有什么區(qū)別歪架,底層的一些區(qū)別如: flutter_web 中的 Canvas 是 EngineCanvas 抽象,內(nèi)部會(huì)借助 dart2js 的能力去生成標(biāo)簽霹陡。
- React Native 平臺(tái)關(guān)聯(lián)性太強(qiáng)牡拇,而 Flutter 在多平臺(tái)上優(yōu)勢(shì)明顯。我們期待官方幫我們解決大部分的適配問(wèn)題穆律。
Flutter 的平臺(tái)無(wú)關(guān)能力能帶來(lái)什么惠呼?
1、某些功能頁(yè)面峦耘,可以一套代碼實(shí)現(xiàn)剔蹋,利用插件安裝引入,在web辅髓、移動(dòng)app泣崩、甚至 pc 上,都可以編譯出對(duì)應(yīng)平臺(tái)的高性能代碼洛口,而不會(huì)像 Weex 等一樣存在各種兼容問(wèn)題矫付。
2、在應(yīng)用上可以快速實(shí)現(xiàn)“降級(jí)策略”第焰,比如某種情況下應(yīng)用產(chǎn)生奔潰了买优,可以替換為同等 UI 的 h5 顯示,而這些代碼只需要維護(hù)一份挺举。
資源推薦
Github : https://github.com/CarGuo
RTC社區(qū) : https://rtcdeveloper.com