作为前端,我们经常听到flutter,那么它又是什么呢?
官方来说Flutter是一个UI SDK ( Software Development Kit ) 可以进行移动端(iOS、Android ) ,Web端( Beta ),桌面( technical preview ),跨平台解决方案;移动端目前已经很多公司在用,Google、阿里、腾讯 特别是阿里的咸鱼团队,为Flutter做了非常多的贡献; Flutter它是有一统大前端的野心的,并且它正在侵蚀iOS、Android这些原生开发;
它有四大特点美观、快速、高效、开放。
- 美观︰ 使用Flutter内置美丽的Material Design和Cupertino widget 、丰富的motion API、平滑而自然的滑动效果和平台感知,为用户带来全新体验。
- 快速: Flutter的UI渲染性能很好。在生产环境下,Flutter将代码编译成机器码执行,并充分利用GPU的图形加速能力,因此使用Flutter开发的移动应用即使在低配手机上也能实现每秒60帧的UI渲染速度。 Flutter引擎使用C++编写,包括高效的Skia 2D渲染引擎,Dart运行时和文本渲染库。
- 高效: 有着和前端几大框架(vue、angular、react)同样的Hot Reload(热重载)。
- 开放:Flutter是开放的,它是一个完全开源的项目。
它被常常用于希望可以通过一套代码开发出可以同时运行在iOS和Android两个系统上的应用程序,而对于公司而言,完整的软件系统需要两种工程师的成本是非常高的
- iOS端使用OC、Swift来进行开发,大部分iOS程序员目前这两个都需要掌握;(iOS开发工程师)
- Android端使用Java、Kotlin来进行开发,使用Java开发Android会更多一些;(Android开发工程师)
在此之前跨平台有几种:
基于 JavaScript 和 WebView的跨平台:最早出现的跨平台框架是基于 JavaScript 和 WebView,代表框架有PhoneGap,Apache Cordova,Ionic 等等,主要是通过HTML来构建自己的界面,再将其显示在各个平台的WebView中,但是它默认是不能调用本地的一些服务的(比如相机、 蓝牙等),所以需要通过JavaScript进行桥接调用原生的一些代码来完成某些功能。但是,它本身的体验、性能都并不理想,而且开发过程 中的坑非常多。
备受欢迎的React Native:在寻求最佳跨平台解决方案的过程中,无疑React Native 是在flutter前最优秀的一个,React Native (简称RN)是Facebook于2015年4月开源的跨平台 移动应用开发框架,是Facebook早先开源的JS框架 React 在原生 移动应用平台的衍生产物,目前支持iOS和安卓两大平台,它使用JavaScript语言,类似于HTML的JSX,以及CSS来开发移 动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可 以进入移动应用开发领域。并且在保留基本渲染能力的基础上,用原生自带的 UI 组件实现核心的渲染引擎,从而保证了良好的渲染性能。但是,由于RN的本质是通过JavaScript VM调用原生接口,通信 相对比较低效,而且框架本身不负责渲染,而是是间接通过原生 进行渲染的,所在RN上做出非常多贡献的Airbnb之前就宣布放弃RN, 而转向Native进行开发。
Flutter:Flutter利用Skia绘图引擎,直接通过CPU、GPU进行绘制,不需要依赖任何原生的控件,Android操作系统中,我们编写的原生控件实际上也是依赖于Skia进行绘制,所以flutter在某些Android操作系统上甚至还要高于原生(因为原生Android中的Skia必须随着操作系统进行更新,而Flutter SDK中总是保持最新的),而类似于RN的框架,必须通过某些桥接的方式先转成原生进行调用,之后再进行渲染。React Native 之类的框架,只是通过 JavaScript 虚拟机扩展调用系统组件,由 Android 和 iOS 系统进行组件的渲染,Flutter 是自己完成了组件渲染的闭环。性能方面在RN之上。
在前端显示中无论是视频还是GIF图片还是操作系统给我们看到的图形化界面中的画面,都是图像。 举个以前的列子:连环画,只要翻得足够快。我们就能在书上看到动画的效果。当图片连续播放的频率超过16帧(16张图片),人眼就会感觉非常流畅,当少于16帧时,会感觉到卡顿
所以我们平时看到的电影,通常都是24帧或者30帧的。
帧率和刷新率的关系
请注意区分帧率(fps):Frames Per Second ;刷新率:显示器的频率,比如iPhone的 60Hz、iPad Pro的 120Hz。
CPU/GPU 向 Buffer 中生成图像,屏幕从 Buffer 中取 图像、刷新后显示。
理想的情况是帧率和刷新频率相等,每绘制一帧,屏幕 显示一帧。 但是实际往往它们的大小是不同的。 如果没有锁来控制同步,很容易出现问题。
例如,当帧率大于刷新频率,当屏幕还没有刷新第1 帧的时候,GPU 已经在生成第2帧了,从上往下开始覆盖第 n-1 帧的数据,当屏幕开始刷新第 n-1 帧的时候,Buffer 中的数据上半部分是第n帧数据, 而下半部分是第 n-1 帧的数据 显示出来的图像就会出现上半部分和下半部分明显偏差 的现象,我们称之为 “tearing”(撕裂)。解决这个问题的方法是双重缓存(Double Buffer)两个缓存区分别为 Back Buffer 和 Frame Buffer。 GPU 向 Back Buffer 中写数据,屏幕从 Frame Buffer 中读数据。 VSync 信号负责调度从 Back Buffer 到 Frame Buffer 的复制操作 当然底层不是通过复制,而是通过交换内存地址方式,所以可以瞬 间完成,效率是非常高的; 工程流程: 在某个时间点,一个屏幕刷新周期完成,VSync 信号产生,先完成 复制操作,然后通知 CPU/GPU 绘制下一帧图像。 复制操作完成后屏幕开始下一个刷新周期,即将刚复制到 Frame
Buffer 的数据显示到屏幕上。 在这种模型下,只有当 VSync 信号产生时,CPU/GPU 才会开始绘制。当 CPU/GPU 绘制一帧的时间过长(比如超过16ms)时,会产生 Jank(画面停顿,甚至空白)。 蓝色代表 CPU 生成 Display List; 绿色代表 GPU 执行 Display List 中的命令从而生成帧; 黄色代表生成帧完成,在屏幕上显示; 双缓存模型中: CPU生成蓝色B的数据,由GPU进行B的绘制,但是这个过长由于过长, 那么第二个A就产生了Jank。 B在屏幕上显示之后,发出Vsync信号,A开始绘制,但是由于绘制时间 过长,第二个B位置又产生了Jank。在此基础上三重缓存(Triple Buffer)解决双重缓存的问题,在第二个A展示,Vsync信号发出后,直接绘制C Buffer 在第一个B展示,Vsync信号发出后,绘制A Buffer 因为C已经在缓存中,可以直接从缓存中取出C Buff来进行展示,依次类推其实本质是在每次Vsync信号发出后,多缓存一个Buffer作为备用。
Flutter绘制原理图:GPU将信号同步到 UI 线程 UI 线程用Dart来构建图层树 图层树在GPU 线程进行合成 合成后的视图数据提供给Skia引擎并通过OpenGL 或者 Vulkan将显示内容提供给GPU。什么是Skia引擎?Skia就是 Flutter向 GPU提供数据的途径。Skia(全称Skia Graphics Library(SGL))是一个由C++编写的开源图形库,能在低端设备如手机上呈现高质量的2D图形,最初由Skia公司开发,后被Google收购应用于Android、Google Chrome、Chrome OS等等当中。目前,Skia 已然是 Android 官方的图像渲染引擎了,因此 Flutter AndroidSDK 无需内嵌 Skia 引擎就可以获得天然的 Skia 支持;而对于 iOS 平台来说,由于 Skia 是跨平台的,因此它作为 Flutter iOS 渲染引擎被嵌入到 Flutter 的 iOS SDK 中,替代了 iOS 闭源的 Core Graphics/CoreAnimation/Core Text,这也正是 Flutter iOS SDK 打包的 Ap包体积比Android 要大一些的原因。底层渲染能力统一了,上层开发接口和功能体验也就随即统一了,开发者再也不用操心平台相关的渲染特性了。也就是说,Skia 保证了同一套代码调用在Android 和 iOS 平台上的渲染效果是完全一致的。