都 9012 年了,Flutter 有多火,就不须要我多说了,以前掘金首页顶着好长一段时间的 Flutter 视频教程推广足以证实。html
那么正如必需要先 ”入门“ 才能 ”出门“,那么前端劝退 Flutter 前也必须得先了解 Flutter。前端
本文就之前端的角度来给你们捋一捋:在前端眼中,Flutter 的开发到底有何不一样? vue
......而后劝退=_=。【想直接被劝退请滑到最后】react
首先,什么是 Flutter?android
官网解释:ios
Flutter是一款 Google 开源的 SDK,可跨平台地为移动端,Web 端,桌面端构建高性能的应用。
固然,固然,虽然说是Web端桌面端都能开发,可是咱们更多地会着重于 flutter 的移动端跨平台开发功能。git
那么,在 flutter以前,其实就有不少跨平台开发的框架了,知名的有 C# 的 Xamarin, 用 js 的有 nativescript ,阿里的 weex 以及你们都比较熟悉的 react native,那么名气不大的就更多了程序员
因此,flutter 在一堆跨平台开发框架中凭什么脱颖而出呢?github
前面的这些都是其次,最关键的是什么呢?web
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 的性能问题,社区又推出了另一种方案
如图所示,React native ,Weex 等框架,是用前端语言描述系统 OEM 之类 实现跨平台,简单的来讲,是经过写 js 配置页面布局,而后经过 react native 解析成原生的控件。
这样的作法,就明显提升了性能,由于实质上渲染出来的,仍是原生的控件。
可是,即使性能提升了,可是依然达不到原生的层次,由于 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