干货|Flutter 原理与闲鱼深度实践

王康(正物)—— Flutter 官方成员 阿里巴巴技术专家,以前主要负责 Flutter 在闲鱼中的混合开发体系,目前重点关注 Flutter 深刻度以及生态相关的工做。本文将分享三方面内容, Flutter 的原理、 Flutter 在闲鱼中的应用,最后介绍咱们在深度方面的一些探索。

0一、Flutter 原理

当咱们谈到跨平台框架时,可能会想到不少备选方案。包括早期的 HTML 和 Cordova , 后来的 React Native , Weex ,以及这两年非常流行的 Flutter ,它们都在不一样阶段不一样程度上解决了咱们对跨平台的诉求。若是咱们从一些关键指标包括动态性、性能来观察,他们的区别还比较明显。编程

HTML 和 Cordova 具备最好的动态性,但他们的性能倒是最差的,RN / Weex 具备良好的动态性。Flutter 则是一个纯原生的设计,其设计使它天生具备很好的性能与跨端一致性。后端

Flutter 是如何实现优秀的性能和跨端一致性的呢?从设计上能够看出 Flutter 在操做系统之上包含了三个层次。最下面是平台相关的嵌入层,其向上提供一个 Surface 用以绘制,创建了相关的线程模型和事件循环机制。在此之上则是一个平台无关的引擎,包括用于绘制的 Skia ;Dart 的运行时,开发模式下包括一个解释器;还有一部分是文本绘制相关内容。最上面就是用 Dart 语言编写的 Flutter 框架,也是咱们最常接触到的内容。Flutter 框架包含一个完整分层的 UI 框架,从基础的 Foundation 库,到动画手势,再到渲染,之上又提供了各类丰富的 Widget 库。为了方便开发者使用, Flutter 还提供了两套不一样风格的组件库,针对安卓的 Material Design 的组件库和针对 iOS 的 Cupertino 风格的组件库。框架

从这个设计能够看出,Flutter 和平台相关的内容,其实只提供 Surface 和线程/事件循环模型的嵌入层部分。这种相似用游戏引擎的方式来开发应用的设计很好解释了为何它具备优秀的跨端一致性。工具

咱们经常说 Flutter 具备这样的几个特色:布局

  • 精美

丰富的 Widget 库、 Material Design 和 Cupertino 风格的系统库、组合式的 API 、像素级的控制力可使开发者便捷地构建精美的应用。性能

  • 高效开发&执行快速

Dart 语言是为数很少同时支持 JIT 和 AOT 编译的语言。开发期使用 JIT 编译,支持了广受欢迎的热重载功能,开发者能够像 PS 图片同样来开发应用,开发效率高。发布后 Flutter 使用 AOT 编译, Dart 代码最终被编译成 ARM 汇编指令,运行快速。测试

  • 开放

Flutter 是开源项目,其整个的开发,工做流都是彻底遵循开源项目的运做来完成的。gradle

0二、Flutter 在闲鱼中的应用

说完 Flutter 原理,咱们来看 Flutter 在闲鱼中的应用。在咱们的研发中有几个核心关注的问题。优化

  • 开发效率

闲鱼技术是一个相对较小的团队,但业务需求比较重,开发人员少需求多,这种状况下效率就很是重要。还有部分缘由是 iOS 安卓两端开发资源不均衡的问题,动画

  • 用户体验

咱们的设计要求咱们具备很好的跨端一致性,其设计也是同一套风格。

  • 执行性能

不论是复杂的交互仍是动画,都要求其具备不错的性能。

Flutter 的设计很好地知足了闲鱼业务研发关注的这些问题,这也是咱们采用它的缘由。

咱们怎么样让 Flutter 从无到有地在闲鱼中落地与上线?这里面包括前期的调研,研发期的混合开发体系,以及如何保质保量在线上运行。

2017 年,咱们去接触和调研 Flutter ,其当时还处在 Alpha 阶段。

咱们须要去了解它的原理,看它是如何具备所宣称的诸多优点;对其性能作测试,看可否知足要求;包大小的增长怎么样,这个量是否可承受;音视频调的出发点在于业务场景,咱们的详情和发布页面包括了不少图片和视频;工具链上 Flutter的开发体验如何;咱们甚至作了一个 MVP Demo ,这个产品中咱们实现了包括发布,详情、个人页面等主要设计与逻辑;此外咱们还很关注其社区的成熟度,确保在遇到问题时,能够经过本身对原理的理解或者社区去解决问题。

要使用 Flutter 咱们就会面临一个混合研发体系的问题。其最开始的设计是面向纯 Flutter 开发的应用。而咱们的应用是在原生项目中嵌入 Flutter ,也就是 Add2App 。事实上在国内,即使是一个纯 Flutter 的应用,不少时候,由于二方、三方库的缘由,也会成为一个混合工程。经过咱们的实践与影响, Add2App 也变成了 Flutter 演进的重要方向。

工程层面上,咱们的团队中存在两个视角。一个是传统的 Native 开发的视角,一个是 Flutter 视角。咱们并无直接使用 Github 上的 Flutter 项目,主要是由于可控性的问题。由于国内的安卓碎片化以及 ROM 中 opengl 的实现不规范,使咱们不得不存在一些针对性的处理逻辑,也就是引擎定制。其产物经过定制的 Flutter 最终被 fwn 工程所使用。fwn 工程包含了实际 Flutter 业务,其 Flutter 代码经过产物集成的方式,经过 pod( iOS ) ,和 gradle ( Android ),最终集成到原生项目中。

混合开发不只包括工程体系,也包括页面侧的逻辑。咱们一开始就涉及到了混合页面体系,以 Android 为例简要介绍下原理。每一个 Flutter 页面对应了一个原生的 BoostFlutterActivity , BoostFlutterActivity 经过各自的 BoostFlutterView 去绑定单例的 FlutterEngine 。当 Flutter 页面在作切换时 BoostFlutterActivity 也会同步切换,将 FlutterEngine 动态地 Detach 和 Attach 。Native 和 Flutter 之间能够互相关闭和打开页面, Native 的生命周期也会同步到 Flutter 侧。

Flutter 支持 UI 构建以及逻辑实现,但可能咱们还须要去获取 wifi 状态或电量等系统状态。

面对这样的场景, Flutter 提供了不少机制去扩展应用。以获取电量为例, Flutter 提供了 Channel 机制用于同 Native 之间的双向通讯。Dart 代码在 Release 下会变成汇编代码,直接调用到 Engine ( C++ ),再调用到 OC (直接)或 JAVA (经过 JNI 间接),这种设计下的性能是原生体验。

Flutter 不只在逻辑侧提供了 Channel 机制去扩展应用,在渲染相关也提供了一些机制去作更多。咱们写的 Flutter 视图布局最终会经过 DartRuntime 调用到 Engine 中的 LayerTree->Paint 方法。在这个渲染管线中, LayerTree 会调用到 SkCanva->Draw ,最终经过 PresentRenderBuffer / SwapBuffer 将内容绘制到 GPU 上。LayerTree 中,包含不少种 Layer ,其中有一个特殊的 TextureLayer 可用于扩展。

以 Android 为例, TextureLayer 能够在 SurfaceTexture 的帮助下,同一个 Surface 相关联。基于 Surface 能够将视频播放的内容传入并完成渲染,或者结合 VirtualDisplay 和 Presentation ,完成 NativeView 的嵌入。须要注意的是,由于 VirtualDisplay API 的限制,此部分的逻辑须要 API Level 在 20 及其以上。

也就是说 Flutter 提供了 Channel 机制用来扩展系统特性相关的逻辑,经过 Texture 机制来支持视频播放器等场景和原生视图的嵌入。

在开发过程当中咱们其实也遇到不少问题,不论是混合栈,或者是视频嵌入, iOS 兼容等,不少今天已经再也不是问题, 但我仍是想和你们分享下其中的一些思路。首先了解各层面原理是很重要的, Flutter 自己是一整套庞大完整的内容,针对不一样层次团队中都应该有相关的同窗有必定理解;要有能力识别出关键问题;能够复现和定位问题,提供最小化的 Demo 用于复现它,在经过社区解决问题的场景下,最小的可复现的 Demo 是尤为重要的;还有就是要同社区有紧密的联系与合做。

咱们不只要关注技术自己,也必定要保证业务稳定。这里有一些手段来和你们分享。用灰度来发现那些容易发现的问题,用分桶和降级策略逐渐增长 Flutter 的业务比例,经过线上 APM 去监控质量,这些手段来保障质量。

总的来看,目前咱们有 20 多个页面来使用 Flutter 构建, Crash 水平在万分之一的数量级,详情页等帧率在 52 帧以上,可交互的页面加载时长是 300 毫秒。

这些是咱们目前使用 Flutter 开发的部分页面,包括详情发布、个人等。涉及到的设计元素较多,包括视频、图片、聊天、评论、拍摄等比较完备的内容。咱们最先使用详情和发布来验证 Flutter ,也是要看 Flutter 可否支撑业务场景最复杂的状况,此外也须要分桶与降级的机制来保障最坏状况下的业务可用性。背后的演进并不容易,也是个逐渐改善解决的过程,但这并非原理上的大问题,不少是细节上的问题,典型如安卓上面的碎片化问题。

除了业务落地外,咱们也作了一些体系化的建设,这里面不少内容都同 Native 侧。就 Flutter 而言,从下往上,包括一些针对 Flutter 的 SDK ,像其特有的 APM 采集;大量 SDK 的桥接;在其上,构建用于 Flutter 开发的编程框架,如 Fish Redux , FlutterBoost 等,最终去支撑各个 Flutter 业务的研发。

0三、Flutter 深度实践

分享完 Flutter 在闲鱼中的应用,接下来介绍咱们的一些深度实践。

在 Engine 侧,主要解决 Android 碎片化所带来的问题以及 iOS 上的内存优化。

在 Dart 侧的工做主要围绕着 Dill 展开,咱们开发了一个基于 Dill 编织的 AOP 框架,提供了一种新的方式来实现中间语言层面的代码编织。基于此,咱们也正在作 JSON 转换,轻量级反射等部分的内容。

在 Flutter 侧,咱们的工做包括 APM , FlutterBoost , FishRedux 等面向业务研发的开发框架。

在 UI 部分,咱们也在作一些图片转代码部分的工做。

简单介绍下 AOP 框架和 UI To Code 两部分的工做。

若是想去解决 AOP For Flutter 的问题,有哪些问题须要解决呢?首先咱们要描述清楚这段代码,是想对哪一个库、哪一个类的哪一个方法去作怎么样的操做;要让 AOP 代码没有侵入性,使原生代码和 AOP 代码能够分开编写,并最终在合适层面进行编织;咱们还须要一种机制,去提取散落各处的注解形式的切面逻辑,并将其应用到目标方法中去。

在 AspectD 的设计中,经过提供面向 Dart 的 Aspect 设计,咱们解决了描述切面的问题;经过提供基于 Kernel to Kernel Transform的Transformer ,咱们解决了提取注解和编织的问题。

相对于传统 AOP 框架所提供的 Call 和 Execute 的语法, AspectD 还提供了 Inject 的语法,这主要是由于 Flutter 禁止反射形成的。

目前还有一个问题就是对于构建过程的侵入性。Flutter 的构建过程( flutter tools )和咱们之前的习惯有区别,并无提供太多的扩展点。目前 AspectD 自己有一点对于构建流程的修改,用于拦截原始的 Dill 构建,并用操做过的 Dill 文件替换原始 Dill 文件,这一侵入性同 AOP 自己没有什么关系,咱们正在和 Flutter 团队去解决这一问题。

还有就是咱们在作的 UI To Code 。即经过 UI 去分析版面,识别组件属性和布局,生成中间的 DSL 描述。后端基于此,完成针对 Flutter 的布局推导,树的构建优化与最终代码转化。

0四、总结 & 展望

回顾一下,本文咱们分享了跨平台方案与 Flutter 的原理。在 Flutter 的业务落地中如何去调研问题,如何完成混合开发体系和能力扩展,如何去解决关键问题和保证线上质量;也展开介绍了咱们在 AOP 和 UI To Code 等领域作得一些深刻性工做。

展望将来,咱们谈谈 Flutter 的一些将来的趋势。

首先 Flutter 原理很天然地支持了 Mobile 和 Desktop ,以及神秘的 Fuchsia 系统。针对 Flutter For Web ,我最近也写了一点分析,这是一个实验性的项目,从原理上来讲能够支持 Flutter 代码无成本地运行在 Web 上,但可能存在性能的损失。固然若是业务不是很复杂,或不是很高的性能要求的话,能够考虑尝试下。

除了咱们自身的实践外,咱们也但愿一些大的应用,能够更多地进来。更复杂的应用场景和生态链的支持可让 Flutter 的社群更加完善。

目前咱们如今也在作一些 Flutter China 的工做,核心目标就是完善国内的生态下降你们的开发门槛,让更多的团队可以受益。最后,你们若是有什么问题能够在下方评论区进行交流。

精彩回顾


本文做者:王康(正物)

阅读原文

本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索