移動跨平臺框架Flutter介紹和學習線路

xiangzhihong發表於2019-03-16

Flutter簡介

Flutter是一款移動應用程式SDK,一份程式碼可以同時生成iOS和Android兩個高效能、高保真的應用程式。 Flutter目標是使開發人員能夠交付在不同平臺上都感覺自然流暢的高效能應用程式。我們相容滾動行為、排版、圖示等方面的差異。 在全世界,Flutter正在被越來越多的開發者和組織使用,並且Flutter是完全免費、開源的。

在這裡插入圖片描述

Flutter歷史

說到Flutter,可能很多小夥伴都會以為它是新興的的移動開發框架,其實不然,Flutter的歷史最早可以追溯到2014年10月,其前身是Google內部孵化的Sky專案。

不過,隨著Flutter熱度的上升,特別是2018年Flutter陸續釋出了Beta版和Flutter1.0,給很多小夥伴造成了一個誤區:認為Flutter是最近新興的一個開發框架。最近,Google又釋出了1.2正式版,並且官方也釋出了今年的開發路線(參考Flutter 2019 產品路線圖),可以預見,Flutter將在2019年迎來真正的爆發和成長。

在這裡插入圖片描述
為了方便讀者對Flutter有一個更深的瞭解,下面來看一下Fluter的歷史:

  • 2014.10 - Flutter的前身Sky在GitHub上開源;
  • 2015.10 - 經過一年的開源,Sky正式改名為Flutter;
  • 2017.5 - Google I/O正式向外界公佈了Flutter,這個時候Flutter才正式進去大家的視野;
  • 2018.6 - 距5月Google I/O 1個月的時間,Flutter1.0預覽版;
  • 2018.12 - Flutter1.0釋出,它的釋出將大家對Flutter的學習和研究推到了一個新的起點;
  • 2019.2 - Flutter1.2釋出主要增加對web的支援。
    在這裡插入圖片描述
    通過Flutter的歷史,可以看出Flutter正在逐漸的走向成熟和壯大,它的生態圈也在不斷的發展,所以現在學習Flutter是一個非常的好時機。

Flutter原理

相比React Native和Weex,Flutter實現跨平臺採用了更為徹底的方案(參考移動跨平臺技術方案總結)。它既沒有采用WebView也沒有采用JavaScript,而是自己實現了一臺UI框架,然後直接系統更底層渲染系統上畫UI。所以它採用的開發語言不是JS,而Dart(Dart是物件導向的、類定義的、單繼承的語言。它的語法類似C語言,可以轉譯為JavaScript,支援介面(interfaces)、混入(mixins)、抽象類(abstract classes)、具體化泛型(reified generics)、可選型別(optional typing)和sound type syste)。 據稱Dart語言可以編譯成原生程式碼,直接跟原生通訊,其原理模型圖如下:

在這裡插入圖片描述

同時,Flutter將UI元件和渲染器從平臺移動到應用程式中,這使得它們可以自定義和可擴充套件。Flutter唯一要求系統提供的是canvas,以便定製的UI元件可以出現在裝置的螢幕上,以及訪問事件(觸控,定時器等)和服務(位置、相機等)。這是Flutter可以做到跨平臺而且高效的關鍵。另外Flutter學習了RN的UI程式設計方式,引入了狀態機,更新UI時只更新最小改變區域。

系統的UI框架可以取代,但是系統提供的一些服務是無法取代的。Flutter在跟系統service通訊方式,採用的是一種類似外掛式的方式,或者有點像遠端過程呼叫RPC方式,這種方式據說也要比RN的橋接方式高效。關於RN和Flutter到底誰更優秀,有興趣的讀者可以關注下官方的撕逼大戰React Native 團隊怎麼看待 Flutter 的

Flutter 和 React Native 底層框架對比

React-Native、Weex 核心是通過 Javascript 開發,執行時需要 Javascript 直譯器,UI 是通過原生控制元件渲染。Flutter 與用於構建移動應用程式的其它大多數框架不同,因為 Flutter 既不使用 WebView,也不使用作業系統的原生控制元件。 相反,Flutter 使用自己的高效能渲染引擎來繪 制 widget。Flutter 使用 C、C ++、Dart 和 Skia(2D渲染引擎)構建。

在這裡插入圖片描述

Skia 是一個 2D的繪圖引擎庫,其前身是一個向量繪圖軟體,Chrome 和 Android 均採用 Skia 作為繪圖引擎。Android 自帶了 Skia,所以 Flutter Android SDK要比 iOS SDK小很多。

在 ReactNative 中,引入了虛擬 DOM 來減少DOM的迴流和重繪,系統將虛擬 DOM 與真正的 DOM 進行比較,生成一組最小的更改,然後執行這些更改,以更新真正的 DOM。最後,平臺重新繪製真實的 DOM 到畫布中。

React Native 是移動開發的一大進步,並且是 Flutter 的靈感來源,但 Flutter 更進一步。 在 Flutter 中,UI 元件和渲染器已經從平臺中整合到使用者的應用程式中。沒有系統 UI 元件可以操作,所以原來虛擬控制元件樹的地方現在是真實的控制元件樹,Flutter 渲染 UI 控制元件樹並將其繪製到平臺畫布上。

如果說非要比較 Flutter 和 React Native的優勢,可以參考下面幾點:

UI 一致性

Flutter 因為是自己做的渲染,因此在iOS和Android的效果基本完全一致。 React Native存在將RN控制元件轉換為對應平臺原生控制元件的過程,存在一定的差異(如之前在調研裡提到過的Button在iOS和Android下面顯示效果不一樣)。

動態化技術

Flutter使用的Dart語言,支援AOT和JIT兩種模式,在Dev時候,通過JIT可以實現熱過載,開發者可以即時的看到程式碼修改的效果。而在Release Build的時候,通過AOT事先編譯,來最大化的優化效能。因此目前Flutter不支援程式碼的熱更新,不過在Flutter 2019 產品路線圖)可以看到這方面的訊息。

ReactNative 的程式碼通過載入 JSBundle.js執行,JSBundle.js可以儲存在本地,也可以通過遠端載入。目前有很多RN的熱更新方案供選擇。

App體積

Flutter iOS空專案 30M左右,Android空專案 7M左右。 (iOS需要額外整合Skia) React Native iOS空專案 3M左右,Android20M左右。(Android會加入OKHttp導致體積增大)

Flutter 部分的底層功能在 Android 系統上已經有實現,因此 Android 上適配要好(RN在 Android 上有可能遇到相容性問題)。

Flutter的優勢

執行效率上,Flutter和ReactNative都可以達到理論上的60幀的重新整理率,來實現「Native般的流暢體驗」,Flutter是全Native在執行,基於底層程式碼(Android 上為 C++ with NDK,iOS 上為 C++ with LLVM),而ReactNative是Native控制元件 + JavaScript程式碼,實際效能上,Flutter應該優於ReactNative,據官方文件,Flutter可以在支援的裝置上達到120FPS,而ReactNative的文件上,只提到了可以達到60FPS。

相容性上,Flutter 提供的 widget 都是基於 skia來實現和精心定製的,與具體平臺沒關,所以能保持很高的跨 os 跨 os version 的相容性。 Flutter 從更基礎的層去抹平平臺差異,站在了更寬廣、更可控的一個基礎平臺上去演變和發展。 Flutter 官方提供了大部分 Material Design 控制元件的實現(甚至比 Android Design Support 實現的更多)。

Flutter開發語言Dart

為什麼要使用Dart語言

學習Flutter就不得不提到Dart,那Flutter和Dart有什麼關係?確實有關係,早期的Flutter團隊評估了十多種語言,並選擇了Dart,因為它符合他們構建使用者介面的方式,讀者可以去八卦下為什麼要使用Dart語言的推文

Dart能成為Flutter不可或缺的一部分,根本原因還是因為其具有以下特性:

  • 1)Dart是AOT(Ahead Of Time)編譯的,編譯成快速、可預測的原生程式碼,使Flutter幾乎都可以使用Dart編寫。這不僅使Flutter變得更快,而且幾乎所有的東西(包括所有的小部件)都可以定製;
  • 2)Dart也可以JIT(Just In Time)編譯,開發週期異常快,工作流顛覆常規(包括Flutter流行的亞秒級有狀態熱過載);
  • 3)Dart可以更輕鬆地建立以60fps執行的流暢動畫和轉場。Dart可以在沒有鎖的情況下進行物件分配和垃圾回收。就像JavaScript一樣,Dart避免了搶佔式排程和共享記憶體(因而也不需要鎖)。由於Flutter應用程式被編譯為原生程式碼,因此它們不需要在領域之間建立緩慢的橋樑(例如,JavaScript到原生程式碼)。它的啟動速度也快得多;
  • 4)Dart使Flutter不需要單獨的宣告式佈局語言,如JSX或XML,或單獨的視覺化介面構建器,因為Dart的宣告式程式設計佈局易於閱讀和視覺化。所有的佈局使用一種語言,聚集在一處,Flutter很容易提供高階工具,使佈局更簡單;
  • 5)開發人員發現Dart特別容易學習,因為它具有靜態和動態語言使用者都熟悉的特性。

在這裡插入圖片描述

編譯與執行

歷史上,計算機語言分為兩組:靜態語言(例如,Fortran和C,其中變數型別是在編譯時靜態指定的)和動態語言(例如,Smalltalk和JavaScript,其中變數的型別可以在執行時改變)。靜態語言通常編譯成目標機器的本地機器程式碼(或彙編程式碼)程式,該程式在執行時直接由硬體執行。動態語言由直譯器執行,不產生機器語言程式碼。

當然,事情後來變得複雜得多。虛擬機器(VM)的概念開始流行,它其實只是一個高階的直譯器,用軟體模擬硬體裝置。虛擬機器使語言移植到新的硬體平臺更容易。因此,VM的輸入語言常常是中間語言。例如,一種程式語言(如Java)被編譯成中間語言(位元組碼),然後在VM(JVM)中執行。

另外,現在有即時(JIT)編譯器。JIT編譯器在程式執行期間執行,即時編譯程式碼。原先在程式建立期間(執行時之前)執行的編譯器現在稱為AOT編譯器。

一般來說,只有靜態語言才適合AOT編譯為本地機器程式碼,因為機器語言通常需要知道資料的型別,而動態語言中的型別事先並不確定。因此,動態語言通常被解釋或JIT編譯。

在開發過程中AOT編譯,開發週期(從更改程式到能夠執行程式以檢視更改結果的時間)總是很慢。但是AOT編譯產生的程式可以更可預測地執行,並且執行時不需要停下來分析和編譯。AOT編譯的程式也更快地開始執行(因為它們已經被編譯)。

相反,JIT編譯提供了更快的開發週期,但可能導致執行速度較慢或時快時慢。特別是,JIT編譯器啟動較慢,因為當程式開始執行時,JIT編譯器必須在程式碼執行之前進行分析和編譯。研究表明,如果開始執行需要超過幾秒鐘,許多人將放棄應用。

Dart的編譯與執行

在創造Dart之前,Dart團隊成員在高階編譯器和虛擬機器上做了開創性的工作,包括動態語言(如JavaScript的V8引擎和Smalltalk的Strongtalk)以及靜態語言(如用於Java的Hotspot編譯器)。他們利用這些經驗使Dart在編譯和執行方面非常靈活。

Dart是同時非常適合AOT編譯和JIT編譯的少數語言之一(也許是唯一的“主流”語言)。支援這兩種編譯方式為Dart和(特別是)Flutter提供了顯著的優勢。

JIT編譯在開發過程中使用,編譯器速度特別快。然後,當一個應用程式準備釋出時,它被AOT編譯。因此,藉助先進的工具和編譯器,Dart具有兩全其美的優勢:極快的開發週期、快速的執行速度和極短啟動時間。

Dart在編譯和執行方面的靈活性並不止於此。例如,Dart可以編譯成JavaScript,所以瀏覽器可以執行。這允許在移動應用和網路應用之間重複使用程式碼。開發人員報告他們的移動和網路應用程式之間的程式碼重用率高達70%。通過將Dart編譯為原生程式碼,或者編譯為JavaScript並將其與node.js一起使用,Dart也可以在伺服器上使用。

最後,Dart還提供了一個獨立的虛擬機器(本質上就像直譯器一樣),虛擬機器使用Dart語言本身作為其中間語言。

Dart可以進行高效的AOT編譯或JIT編譯、解釋或轉譯成其他語言。Dart編譯和執行不僅非常靈活,而且速度特別快。

AOT編譯和“橋”

前面討論過一個有助於保持順暢的特性,那就是Dart能AOT編譯為本地機器碼。預編譯的AOT程式碼比JIT更具可預測性,因為在執行時不需要暫停執行JIT分析或編譯。

然而,AOT編譯程式碼還有一個更大的優勢,那就是避免了“JavaScript橋樑”。當動態語言(如JavaScript)需要與平臺上的原生程式碼互操作時,它們必須通過橋進行通訊,這會導致上下文切換,從而必須儲存特別多的狀態(可能會儲存到輔助儲存)。這些上下文切換具有雙重打擊,因為它們不僅會減慢速度,還會導致嚴重的卡頓。

在這裡插入圖片描述

說明:即使編譯後的程式碼也可能需要一個介面來與平臺程式碼進行互動,並且這也可以稱為橋,但它通常比動態語言所需的橋快幾個數量級。另外,由於Dart允許將小部件等內容移至應用程式中,因此減少了橋接的需求。

佈局

Dart的另一個好處是,Flutter不會從程式中拆分出額外的模板或佈局語言,如JSX或XML,也不需要單獨的可視佈局工具。以下是一個簡單的Flutter檢視,用Dart編寫:

new Center(child:
  new Column(children: [
    new Text('Hello, World!'),
    new Icon(Icons.star, color: Colors.green),
  ])
)
複製程式碼

並且隨著Dart 2的釋出,上面的程式碼也變得越來越可讀,因為new和const關鍵字變得可選,所以靜態佈局看起來像是用宣告式佈局語言編寫的:

Center(child:
  Column(children: [
    Text('Hello, World!'),
    Icon(Icons.star, color: Colors.green),
  ])
)
複製程式碼

至於,困擾原生開發人員的一個問題是:為什麼缺乏專門的佈局語言怎麼會被稱為優勢呢?原生開發人員可以在下面的文章中找到答案:“為什麼原生應用程式開發人員應認真看待Flutter

學習路線

學習任何一門技術,最主要的渠道就是官方資料,由於是Google的產品,因此從一開始就受到很多開發者的喜愛,因此其社群建設也相對較快,讀者可以現場Flutter中文社群瞭解一些Flutter開發的基礎,然後再結合一些開源專案進行學習。

在這裡插入圖片描述

Fluuter網上的學習資料也很多,可以參考下面的連結進行深入的學習:Flutter學習線路

在這裡插入圖片描述

參考:

Flutter學習線路

Flutter中文社群

Flutter 入門教程

Flutter實戰

React Native VS Flutter

相關文章