都 9012 年了,Flutter 有多火,就不須要我多說了,以前掘金首頁頂着好長一段時間的 Flutter 視頻教程推廣足以證實。css
那麼正如必需要先 」入門「 才能 」出門「,那麼前端勸退 Flutter 前也必須得先了解 Flutter。html
本文就之前端的角度來給你們捋一捋:在前端眼中,Flutter 的開發到底有何不一樣?前端
......而後勸退=_=。【想直接被勸退請滑到最後】vue
首先,什麼是 Flutter?react
官網解釋:android
Flutter是一款 Google 開源的 SDK,可跨平臺地爲移動端,Web 端,桌面端構建高性能的應用。ios
固然,固然,雖然說是Web端桌面端都能開發,可是咱們更多地會着重於 flutter 的移動端跨平臺開發功能。git
那麼,在 flutter以前,其實就有不少跨平臺開發的框架了,知名的有 C# 的 Xamarin, 用 js 的有 nativescript ,阿里的 weex 以及你們都比較熟悉的 react native,那麼名氣不大的就更多了 程序員
因此,flutter 在一堆跨平臺開發框架中憑什麼脫穎而出呢?github
前面的這些都是其次,最關鍵的是什麼呢?
Flutter 有個好「爹」!
你們琢磨一下,當下的主流的三大前端框架,react、react native 是 facebook 的,angular 又是 google 的,只有 vue 是沒有大公司背景。事實上社區的不少開源框架,其實都是大企業內部孵化出來的。
有個好爹,背靠 Google 爸爸,含着金鑰匙出生,一看就前途不可估量。框架的穩定性和成長性就能獲得必定保證,給開源社區信心。
這就是,拼爹一時爽,一直拼一直爽。
言歸正傳,這裏提到 flutter 能不侷限於系統 OEM,以及相比其餘跨平臺框架提供更優秀的性能,那麼憑啥就 flutter 那麼秀呢?咱們能夠從 flutter 框架結構上去探索一下。
flutter 的框架結構圖以下:
好了,相信你們不僅一次看到這一張圖了。 懂的可能已經瞭然於胸,不懂的可能仍是一臉懵逼。
這裏仍是簡單說下
從上往下看, 首先是 Framework,Framework 是用 dart 語言寫的,從上往下,
Framework 往下是 Engine, Framework 中的 UI 交互都是有 Engine 來進行繪製渲染的。Engine 層內部會經過 Skia 圖形引擎畫出 UI 組件,Skia 是 Google 開源的 2D 圖形引擎,適用於多個平臺系統,這也是 flutter 能跨平臺的核心元素之一。這也是爲何前面說 flutter 能不侷限系統 OEM 組件的限制。 也就是說,若是你想要本身封裝一個 ant-design 畫風的 flutter UI 框架,你能夠直接經過基礎的 Widget 搭建出本身的 UI 框架。若是底層基礎 UI 知足不了你的需求。你能夠直接用 dart 調用 Skia 圖像引擎的 API,畫出本身的 UI,沒有任何的限制。
最後是 embedded,嵌入層,這一塊是處理平臺差別性的事情,從而可以把 flutter 應用嵌入到各個系統平臺。
能夠看到 Flutter 沒有用原生系統上的 OEM,而是用 2D 渲染引擎 skia 直接渲染繪製 UI, 這使得其平臺相關層很低,平臺只是提供一個畫布,剩餘的全部渲染相關的邏輯都在Flutter內部,這就使得它具備了很好的跨端一致性。
以上就是 flutter 跨平臺開發的結構了, 那麼這樣設計的優越性在哪呢?咱們能夠對比下其餘應用開發的架構。
首先咱們來看下原生APP開發的架構設計,通常一個 App,會分爲兩大塊,分別是 UI 渲染和系統服務調用,咱們常說的跨平臺開發,其實就是跨的這兩塊。
原生 App 的 UI ,會經過平臺提供的原生 OEM 控件實現,而系統服務調用,如相機,藍牙等傳感器的使用,也會經過平臺系統提供的 API 來實現
那麼這就會粗線一個問題,不一樣平臺的 OEM 控件和 系統服務調用規範,以及編程語言不統一,Android 使用 Java / Kotlin,而 iOS 使用 Objective-C / Swift,這就產生了平臺差別性。
一個 app 要開發幾套代碼,UI 效果還不必定能保持一致,費時費力。
因而,就產生了跨平臺開發的需求。
咱們來看下常見的跨平臺架構
首先最多見的跨平臺方案,是直接用 webview ,這其實就是咱們常說的 hybrid app 了。
雖然說不一樣平臺的 webview 內核不必定同樣,可是總歸會遵循 w3c 規範, 那麼咱們的前端的代碼能夠運行在平臺的 Webview 上,實現 UI 上的跨平臺開發
而系統服務調用這一塊呢,就經過 bridge 來經過協議來調用原生的方法。
那麼 hybrid app 的方案缺點也是很明顯的, webview 性能比不上原生。
爲了解決這個 webview 的性能問題,社區又推出了另一種方案
這樣的作法,就明顯提升了性能,由於實質上渲染出來的,仍是原生的控件。
可是,即使性能提升了,可是依然達不到原生的層次,由於 RN 是經過 Jscore 解析 jsbunder 文件佈局,和原生直接佈局仍是有那麼一丁點差距的。
另外,使用 react native 並不能避免寫原生的代碼,若是遇到一些平臺相關的複雜問題,仍是不得不深刻到原生庫中進行必要的調整。去年 Airbnb 就由於相似的緣由放棄了 rn。
那麼,用 flutter 就能避免這個問題了麼?咱們來看下 flutter 的架構
前面其實也說過了,flutter 的 UI 渲染是基於 skia 圖像引擎完成的,不依賴任何一個系統平臺,平臺僅僅提供一個畫布,讓 圖像渲染在畫布上。
那麼直接越過原生的渲染機制,從自身的渲染引擎去渲染視圖,這就和原生如出一轍,沒有了中間商賺差價。
二者的渲染性能也提高爲了 二者的渲染引擎之間的比較。
至此,咱們比較了幾種跨平臺架構的 UI 渲染實現,
那麼關於系統服務的調用呢?Flutter 並無消除 跨平臺 系統服務調用的問題,由於硬件設計層面以及編程語言的差別性是客觀存在的,基本沒法避免。
可是不一樣於以前幾種用 bridge 的方式來調用系統服務,flutter 用 Platform channel 的形式去調用系統服務,這裏先跳過,下面的章節會詳細講一下這裏的通訊機制
不一樣於 Web 把頁面分紅了 HTML,CSS,JS, 在 Flutter 中,全部東西都是 widgets 具體 widgets 類型分爲:
全部的 widget 嵌套組合在一塊兒,就構成了一個 flutter app。
關於樣式語法,前端的代碼咱們很熟悉了,用 HTML 和CSS 能快速實現一個簡單的 UI。
咱們來看看一個最基本的盒子模型:
<div class="greybox">
Lorem ipsum
</div>
<style> .greybox { background-color: #e0e0e0; /* grey 300 */ width: 320px; height: 240px; font: 900 24px Georgia; } </style>
複製代碼
var container = Container( // grey box
child: Text(
"Lorem ipsum",
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.w900,
fontFamily: "Georgia",
),
),
width: 320.0,
height: 240.0,
color: Colors.grey[300],
);
複製代碼
在 flutter ,因爲 Flutter 沒有標記語言,咱們須要嵌套一個個 Widget 類來實現咱們的 UI,這裏的 Container Widget類,其實就至關於 div 標籤。
那麼看到這個代碼風格,若是有寫過 非 jsx 的 react 的話,你會發現代碼風格有點像是 React.createElement
的畫風。
React.createElement("div", {
class: "test-c",
style: "width: 10px;"
}, "Hello", React.createElement("span", null, "world!"));
複製代碼
實現一個 UI ,第二個比較重要的點是佈局, 在 Web 前端,實現佈局的核心要點是 CSS 的屬性:
<div class="greybox">
<div class="redbox">
Lorem ipsum
</div>
</div>
<style> .greybox { background-color: #e0e0e0; /* grey 300 */ width: 320px; height: 240px; font: 900 24px Roboto; display: flex; align-items: center; justify-content: center; } .redbox { background-color: #ef5350; /* red 400 */ padding: 16px; color: #ffffff; } </style>
複製代碼
而在 flutter,則須要一些官方提供的樣式類來實現,例如這裏的 BoxDecoration 類來修飾整個盒子,Alignment 肯定文本對齊方式等等
var container = Container( // gray box
child: Center(
child: Container( // red box
child: Text(
"Lorem ipsum",
style: bold24Roboto,
textAlign: TextAlign.center,
),
decoration: BoxDecoration(
color: Colors.red[400],
),
padding: EdgeInsets.all(16.0),
),
alignment: Alignment.center,
),
width: 320.0,
height: 240.0,
color: Colors.grey[300],
);
複製代碼
Web:
<input name="account" />
<div onclick="handleSubmit()">Submit</div>
複製代碼
最後一點是交互,相似於大部分的前端 UI 框架,每一個組件其實都會暴露出一些事件鉤子,
經過這些鉤子,咱們就能夠捕獲到用戶的行爲,從而實現對應的邏輯,
這裏的 demo 就簡單實現了 輸入校驗, 按鈕的點擊提交等基本的交互。
Flutter:
// ...
children: <Widget>[
TextFormField(
decoration: InputDecoration(
hintText: 'Email/Name/Telephone',
labelText: 'Account *',
),
onSaved: (String value) {
loginForm.account = value;
},
validator: (String value) {
if (value.isEmpty) return 'Name is required.';
}
),
RaisedButton(
child: Text(
'Login'
),
onPressed: () {
// print('提交操做');
// dosomething with loginForm
handleSubmit()
},
),
]
複製代碼
其他的還有 路由,動畫,手勢等交互,這裏再也不多說,基本上能用 Web 技術實現的,大都可以在 flutter 實現
能夠看到,flutter 的 UI 部分除了沒有 jsx 以外,其他部分的設計思想與 react 大同小異。
那麼簡單介紹完語法,咱們來實際操做看看,怎麼寫一個 APP
首先怎麼安裝 flutter 開發環境這個就很少說了,官網教程教程已經很完善了
簡單說下目錄結構,經過 flutter
建立出一個工程後,會自動生成這樣的目錄結構,
.
├── android # Android 平臺配置,flutter 自動生成
├── ios # iOS 平臺配置,flutter 自動生成
├── assets # 靜態資源目錄
├── build # 存放構建出的 release 相關文件
├── lib # 業務代碼
├── └── main.dart # app 入口
└── pubspec.yaml # 包管理文件
複製代碼
上手一個框架,固然要來一個經典的 Hello World。
要實現一個 flutter app, 咱們須要 加載 flutter 的基本組件 import 'package:flutter/widgets.dart';
, 而後執行基本的 runApp
, 那麼一個基本的 hello world 就完成了。
// main.dart 文件
import 'package:flutter/widgets.dart';
void main() {
runApp(
Center(
child: Text(
'Hello, world!'
),
),
);
}
複製代碼
效果以下:
能夠看到,若是沒有樣式的話,應用就是一坨黑....
就像在前端開發時咱們喜歡使用的 ant design 或者 iview 之類的 UI 框架,開發 flutter 通常也會用 UI 框架
Flutter 內置兩套 UI 組件,分別是 Material UI 和 Cupertino UI,
如今簡單看下一個 material 風格的APP是怎麼實現的, 首先 import material 組件
new 一個 MaterialApp 組件,配置 title, app bar 等信息,就簡單地生成了個 material 畫風的 app 了。
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
title: 'Hello App',
home: Scaffold(
appBar: AppBar(
title: Text('Hello'),
),
body: Center(
child: Text(
'Hello Flutter',
style: TextStyle(
fontSize: 30
),
)
),
),
)
);
}
複製代碼
更復雜的還能夠在這裏配置路由相關信息,這裏就再也不多說。
經過這些咱們知道怎麼實現一個 flutter app,那麼看到全部有實體的元素,都是稱爲 Widgets, 這裏爲了方便理解,咱們統稱爲組件。
而組件又細分爲 Stateless Widget 和 Stateful Widget,這裏能夠很容易聯想到 react 的 無狀態組件和 有狀態組件
事實上 flutter 的這兩種組件確實和 react 的差很少
咱們首先看下 無狀態組件(StatelessWidget)
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hello App',
home: Scaffold(
appBar: AppBar(
title: Text('Hello'),
),
body: Center(
child: Text(
'Hello Flutter',
style: TextStyle(fontSize: 30),
)),
),
);
}
}
複製代碼
StatelessWidget
對應 react 的函數組件 Functional Component
build
方法對應 react 的 render
方法再來看看 狀態組件(StatefulWidget)
Flutter 的狀態由兩個類組成: 分別是 StatefulWidget 和 State 類。 寫法雖然不一樣,可是概念都大同小異:
StatefulWidget
對應 React.Component
StatefulWidget
類管理父組件傳遞的 Prop
State
類中管理自身的 State
setState
更新狀態class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Counter App',
home: Scaffold(
appBar: AppBar(
title: Text('Counter'),
),
body: Center(
child: Counter(10) ),
),
);
}
}
class Counter extends StatefulWidget {
// 這個類是 state 的配置,能夠在此定義父組件傳遞下來的 prop
final int increaseNum;
// 構造函數
Counter(this.increaseNum);
@override
_CounterState createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _counter = 0;
void _increment() {
print('count: $_counter');
setState(() {
// setState 的回調告訴 flutter 去變動 當前 State, 而且 setState() 的調用會觸發 build() 從而更新視圖
_counter += widget.increaseNum;
});
}
@override
Widget build(BuildContext context) {
// 每次調用 setState 都會觸發 build 方法,同時,相似於 react 的 render 方法,
// flutter 框架爲了讓 從新 build 更加快,也已經對此作了優化
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: _increment,
child: Text('Increment'),
),
Text('Count: $_counter'),
],
);
}
}
複製代碼
學過 React 的同窗,是否是對此有種似曾相識的感受呢?
組件出來了,生命週期還遠麼?
相似 React ,Flutter 也有本身的組件生命週期:
到此咱們的 UI 組件部分就告一段落。
跨平臺開發,「跨」 的除了平臺 UI 部分外,還有跨了前面提到的平臺系統服務調用。
無論是哪個跨平臺開發的解決方案,基本上都是在UI層面去完成跨平臺,一次開發運行多處,可是當你須要完成特定的功能時,好比:打開相冊獲取照片,這在這一層面上就沒法撼動了,你依然須要使用 Native 的方式來完成。
例如 h5 自己是沒法調用系統底層 API 的,在 h5 咱們就會用到 jsbridge 來給 native 發送命令,從而讓 native 調用系統 API。
而在 flutter, 官方提供了一些插件(plugins packages)來實現經常使用的功能,例如:本地圖片選擇,相機功能等,讓咱們可以簡單直接地使用到不一樣平臺的系統接口。
這裏也提供了一個喚起相機的 demo :
import 'package:image_picker/image_picker.dart';
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File _image;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Picker Example'),
),
body: Center(
child: _image == null
? Text('No image selected.')
: Image.file(_image),
),
// 點擊按鈕進行拍照
floatingActionButton: FloatingActionButton(
onPressed: getImage,
tooltip: 'Pick Image',
child: Icon(Icons.add_a_photo),
),
);
}
Future getImage() async {
// 打開相機拍攝,並得到圖片資源
var image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = image;
});
}
}
複製代碼
那麼 插件是怎麼調用 系統服務的呢?這裏就須要用到 flutter 的 methodchannel / platform channel 通訊機制。
如圖所示,flutter 經過 methodchannel 機制來調用不一樣平臺 native 層的 api。因爲代碼最終會被編譯成機器碼,因此這個調用過程基本上和原生調用差很少,都是無損的,不像經過 bridge 方式調用,須要協議轉化。
要本身實現一個 底層服務調用的 FlutterPlugin,能夠參考官方文檔,簡單來講步驟以下:
看了那麼多,是否是感受這不像勸退,而是一篇 Flutter 吹文?
別急,這就勸退了。
Flutter 雖然看起來很強大,可是實際上深刻琢磨一下,其實也有很多侷限性。
你們都知道,國內的流量幾乎都被幾個大公司壟斷, 而 App 的推廣下載成本也很高。
因此各大公司才推出了五花八門的小程序,到目前爲止,已知的有:
微信/百度/支付寶/字節跳動/ QQ 小程序以及快應用等......
爲了快速引流,考慮投入產出比,小公司更願意會用 小程序/快應用/H5 方案,而不是用獲客成本更高的 App 方案。
例如京東的 taro 框架或相似的跨端小程序開發框架,就比 Flutter 更加符合中國特點。
taro 是一個多端統一開發框架,支持用 React 的開發方式編寫一次代碼,生成能運行在微信/百度/支付寶/字節跳動/ QQ 小程序、快應用、H五、React Native 等的應用。
你們能夠看到,整篇下來,除了 react-style 的設計思想以外,flutter 和前端其實關係不大。
江湖傳言道:一切能用js實現的應用,都將用js實現。
可是很惋惜的是,基於各方面的考慮,google 選擇了 dart 這門並不算熱門的語言做爲 flutter 的開發語言,而不是 JavaScript / Typescript。給前端開發接觸 flutter 設置了必定的門檻。
可是,flutter 也不是隻給咱們前端用的,站在前端角度,咱們固然但願用 js/ts咯。 但這對於 Android/ios 等終端開發來講,其實也是一樣須要必定的成本,能夠算是一視同仁了。
那麼又因爲 dart 語言這兩年才被 flutter 帶起來的緣故,以前一直火不起來,直到 flutter 出來後才強行續命。至此 dart 的社區生態,開源庫等等都比較欠缺,不像前端社區,有豐富的 npm 包。
那麼,你們能夠想下,在 flutter 以前,你有聽過 dart 語言麼?
google 爲何用 dart 做爲 flutter 的開發語言呢?
實際上是由於…… dart 也有個好爹 Orz,他的爹也是Google。
看到沒有,有個好爹多麼重要,三線語言 dart 這不就被捧得大紅大紫了麼[滑稽]
flutter 用自繪引擎完全解決了 UI 層面的平臺差別性,可是前面也提到了,系統硬件服務(如相機藍牙等服務)的差別性是無可避免的。
做爲一個純前端來講,理想狀況下,用 flutter 能夠完成全部原生能實現的功能。
但現實每每是不理想的,跨端開發每每會遇到一些平臺相關的問題,如 flutter plugin的相機拍照 ,在某個型號的安卓設備上有點小bug。若是你是個純前端,運氣好的話能在開源社區找到解決方案,運氣很差,只能向終端(iOS/Android)開發尋求技術支持。
那麼,還須要 iOS/Android 開發來兜底的跨端開發框架,仍是一個跨端開發框架麼?
要開發一個成熟的 App,你敢放心交給純前端用 flutter 負責麼?
固然,這並不是是 flutter 弊端,而是全部跨平臺方案共同的問題。要是沒這問題,react native 早就一統江湖了,airbnb 也不至於棄坑 react native了。
只要跨平臺框架還存在須要程序員自行解決的平臺差別bug,那麼 純前端程序員全盤負責移動端開發 就是個僞命題。
那麼,是否是 flutter 就與前端絕緣了呢? 也並不是如此。 若是你要開發一個重 UI 展現 ,調用系統服務比較少的簡單應用,那麼 flutter 是個不錯的選擇。
事實上,能夠看出,最適合用 flutter 的是哪些程序員呢?
既會 iOS 開發,又懂一些 Android 開發,這不須要太精通, 能搜索解決常見終端問題便可的程序員。那麼學 flutter 就是如虎添翼了。
若是真的有前端有志於作一名 flutter 開發工程師,那麼不妨簡單學習下 Android 和 iOS 開發。
互聯網寒冬什麼人才最吃香?
多面手,綜合性人才,爆棧工程師...
勸退完畢。
插播廣告:
深圳 Shopee 長期內推
崗位:前端,後端(要轉go),產品,UI,測試,安卓,IOS,運維 全都要。
薪酬福利:20K-50K😳,7點下班😏,免費水果😍,免費晚餐😊,15天年假👏,14天帶薪病假。 崗位詳情參考。PS: 網投了就不能內推了哦。 簡歷發郵箱:chenweiyu6909@gmail.com 或者加我微信:cwy13920