服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

FlutterEngine 桌面端架构浅析

日期: 来源:阿里巴巴终端技术收集编辑:刘太举(驽良)

1 前言

在钉钉 Flutter 桌面端落地过程中,我们遇到了很多仅仅依赖 Flutter 官方文档无法解决的问题,例如:桌面端集成模式问题、内存泄露问题、卡顿问题、光标焦点异常问题等。由于无法直接通过官方文档得到答案,我们便尝试通过分析源码实现和设计文档来寻找解决办法。虽然最终大部分问题得以解决,但是在这过程中有两点一直困扰我们:

  1. Flutter 生态中桌面端相关资料极少。少部分官方公开资料也仅有比较宽泛的介绍,缺少详细方案设计信息;业界对 FlutterEngine 架构分析和讨论,大多也仅仅设计移动端,桌面端相关内容很少涉及;
  2. FlutterEngine 在移动端和桌面端 Embedder 层设计有较大差异,移动端相关资料/方案无法直接应用到桌面端。

因此我们便萌生了整理一份 Flutter 桌面端资料集的想法。一方面来作为 Flutter 桌面端设计的入门资料,降低大家上手学习桌面端引擎设计的门槛、提升效率;另外一方面也可作为工具手册,为后续我们可能逐步落地的桌面端引擎改造提供技术储备。

本文主要从宏观角度来介绍一下 FlutterEngine 桌面端设计,从发展历史、架构概述、与移动端引擎对比等角度做一下阐述,以期望读者通过本文的介绍,能对 FlutterEngine 桌面端实现方案有一个整体的了解。

2 发展脉络

通过查阅各种资料我们发现,Flutter 目标虽然是提供一套可跨多端的 UI 套件,但是 Flutter Desktop 项目发展最初并未被直接纳入 Flutter 项目。不过 Flutter Desktop 主要技术人员仍然来自 Google 团队,Flutter Desktop 项目前期独立 Flutter 主项目发展,或许是出于项目管理上的考虑。

Flutter Desktop 发展初期 git 项目为 flutter-desktop-embedding[1], 技术讨论组为Desktop Embedding for Flutter[2]。通过分析 git commit 记录以及讨论主题,我们大致可梳理出 Flutter Desktop 发展脉络时间轴:

3 架构对比

Flutter 桌面端与移动端引擎实现差异主要聚焦在两部分:

  1. 是否使用 Embedder API;
  2. 如何处理 Windows Resize。

下面针对上述两点分别介绍一下。

3.1 Embedder API

关于 Flutter 架构设计,最权威的资料当然来自官方团队提供文档(来源[3]):

Flutter 整体设计上三层结构非常清晰,在不同平台实现架构上又会结合平台特点做适当调整和优化:

注:由于 Web 平台下的实现与其它平台有较大差异、且钉钉在实际应用中并未涉及,因此在此不再分析。

无论是移动端还是桌面端,Flutter 三层结构中的 Framework(Dart) 以及 Engine(C++) 实现是共享的,实现上的主要差异聚焦在 Platform 集成上。

在梳理 Flutter Desktop 桌面端发展脉络时我们已经知道,桌面端实现整体建立在 Embedder API 基础之上(Commit[4]):

Embedder API(资料[5])在设计上主要服务于嵌入式场景,即其提供一组平台无关的通用接口,在接口内封装 FlutterEngine 作为「平台无关图形窗口工具套件」的核心实现。使用者仅需按照接口定义传入所需依赖,即可将 Flutter 作为一个动态库接入全新平台。

通过上面的架构图我们可知,Embedder API 在 Flutter 体系内的定位与 Android 和 iOS 是同级的。Flutter Desktop 基于 Embedder API 来实现,在实现上相比移动端自然要多了一层

如果我们以平台接入的视角来分析一下 Flutter 在端侧的架构,那么我们可以得到以下对比图:

由下至上我们对上图做一下简单说明:

  1. Shell 即 FlutterEngine 平台无关的核心实现部分,如 Dart Runtime、Skia等;
  2. Embedder API是 Flutter 封装的平台无关接口层,其主要价值在于封装底层实现、简化接入流程、降低新平台接入成本;
  3. Android/iOS/macOS/Windows Embedder 是平台接入层,各端根据根据平台规则注入 Flutter 运行所依赖的部分,比如 渲染画布、线程管理、插件机制等;
  4. Android/iOS/macOS/Windows Interface是开发接口层,即 Flutter 面向不同平台暴露的使用 API。虽然不同语言暴露 API 的形式可能略有差异,但是在接口语义上四端基本一致。

3.2 Desktop Resize

在进一步分析 FlutterEngine 桌面端源码时,我们发了其相比移动端实现,除了多一层 Embedder API 以外,还有一层用于管理桌面窗口大小变化的模块FlutterResizeSynchronizer

在查阅相关资料之后找到此模块相关的 设计文档

  • How to handle resize in desktop embeddings[6]
  • Handling flutter view resizing on macOS[7]
  • Support double buffering for window resizing[8]

在设计文档中有对此问题的说明:

简单来说即 Flutter 在异步线程渲染与 Window 在主线程变化,会导致出现 Crash、重影等一系列问题。FlutterResizeSynchronizer 的出现即为了解决此类问题。

4 实现分析

本小结我们以 macOS Embedder 为例,来分下一下 Flutter 桌面端集成部分的实现。为了方便移动端的同学更好理解,部分内容会以 iOS 端实现来做对比说明。

4.1 类图

下面这种即根据 3.1 小节的架构简图,结合 FlutterEngine macOS 端实现梳理出的核心类图:

为了便于对比理解,我们在看看 iOS 端对应的核心类图:

通过对比上两张类图,我们可以初步得到以下信息:

  1. 桌面端部分实现相比移动端增加一层跨平台的 Embedder API,虽然理论上可简化部分上层实现,但是因为涉及到多渲染模式图层合成等因素的影响,桌面端整体架构复杂度并不低于移动端
  2. Desktop Resize 主要由 FlutterView 来控制,在移动端端中 FlutterView 实现较薄,主要用于承载 Flutter 所需的画布;但是在桌面端其功能更为复杂,已直接参与到 Flutter 绘制流程中,并在其中起到关键作用;
  3. Shell 层做了较好的抽象,绝大部分场景可做到实现与平台无关;

4.2 流程对比

通过4.1小节的内容我们可知,FlutterEngine 在桌面端和移动端的差异主要聚焦在渲染绘制阶段。

根据 Flutter 官方分享资料我们知道,Flutter 渲染大致分为两个阶段:

  1. 第一阶段主要在 UI 线程工作,大部分由 Dart 层的 Flutter Framework 实现;
  2. 第二阶段在 CPU 线程工作,主要由 FlutterEngine 中的 C++ 层模块实现。

针对以上两点,第一阶段无论什么平台基本都是一致的,下面我们就结合实现大致对比一下 iOS 端与 macOS 端的第二阶段流程差异。

阶段iOSmacOS
1DoDrawDoDraw
2DrawToSurfaceDrawToSurface
3AcquireFrameAcquireFrame
4SubmitSubmit
5PresentTry Present(窗口变化中则同步等待)
6FlushDoFlush

注意:上述流程对比仅供示意说明问题,并非严谨流程图,有很多细节表格中并未体现

阶段 5~6 所示即 3.2 小节讨论到的「Desktop Resize」控制模块,结合 4.1 中的类图,渲染链路最终会沿着红线所表示的链路回到 FlutterView 模块,最终由 FlutterView + FlutterResizeSynchronizer + FlutterResizableBackingStoreProvider + FlutterSurfaceManager 相互配合,完成安全可靠的绘制:

移动端应为不涉及窗口大小变化,因为并无此流程。

通过上述对比我们可知,Flutter 桌面端相比移动端实现,渲染流程主要变化在于增加窗口大小变化管理模块,窗口大小变化和 Flutter 页面渲染存在同步影响

  1. 如果在渲染过程中窗口发生变化,则变化动作需要等待渲染流程结束之后才可响应:可能导致 Native 主进程卡顿;
  2. 如果 Flutter 渲染过程中存在窗口变化,则会在窗口变化结束之后才会响应渲染:可能影响 Flutter 侧动画效果等;

在钉钉桌面端落地过程中,我们即处理过因为上述同步规则导致的 Flutter 页面创建阶段卡顿,最终通过尽量避免 Window 变化的方式来绕过。

5 小结

本文主要梳理了一下 FluttterEngine 桌面端发展脉络,并针对 FlutterEngine 桌面实现核心内容做了梳理。

通过第3和第4两个小节的分析我们可以看到,Flutter Desktop 最初基于 Embedder API 来实现,或许是期望能够通过通用的 Embedder API 来降低接入成本;并且我们通过查阅 flutter-desktop-embedding[9]commit 记录,最初基于 Embedder API 确实可以做到只通过极少的几个文件,即完成 Flutter Mac 端运行的效果:

但是随着场景复杂度的深入,分层过多带来的弊端逐渐显露出来:在核心任何一个功能增强,都需要对 Platform、Embedder、Shell 三层同时做改造,并且因为要保证 Embedder 和 Shell 层的向兼容性,Embedder 层变得越来越臃肿

Embedder 中负责引擎初始化的 FlutterEngineInitialize 函数为例:

  • 其代码行数约有460行
  • 函数入参合法性校验代码有80行
  • 用于配置启动参数的 FlutterProjectArgs 结构体有34的成员;
  • 用于配置渲染模式的 FlutterRenderConfig 内嵌全部4中渲染模式配置,每种配置10+个不同的成员;
  • 大量的函数指针 Callback.

虽然现在无法判断未来 Flutter Desktop 的实现是否会一直基于 Embedder API 来实现,但基于目前时间点来看,基于 Embedder API 带来的扩展复杂度成本已经逐步掩盖了 Embedder API 所带来封装收益

后面我们会进一步分析 FlutterEngine 桌面端核心流程,并尝试去对齐一些目前移动端支持、但桌面端暂未支持的能力,服务于钉钉业务的同时,也希望能为 Flutter 生态贡献一份力量。

参考资料

[1]

flutter-desktop-embedding: https://github.com/google/flutter-desktop-embedding

[2]

Desktop Embedding for Flutter: https://groups.google.com/g/flutter-desktop-embedding-dev

[3]

来源: https://docs.flutter.dev/resources/architectural-overview

[4]

Commit: https://github.com/google/flutter-desktop-embedding/commit/1940026b543a94f1bc791b1f21052d63522013b9

[5]

Embedder API: https://github.com/flutter/flutter/wiki/Custom-Flutter-Engine-Embedders

[6]

How to handle resize in desktop embeddings: https://docs.google.com/document/d/1OTy-qCGdP7tYfrEKCNX9A24sgnx5vshfK6FupfniyxA/edit#

[7]

Handling flutter view resizing on macOS: https://docs.google.com/document/d/1slGllp1Jhde7wkF6snqGhdrZwHV1VVmXeIF3f0t24JU/edit#

[8]

Support double buffering for window resizing: https://docs.google.com/document/d/1allwMZXgX9gGVPguFy3-XydjXEIJgYR1Uhz8Vhm9Rrs/edit#

[9]

flutter-desktop-embedding: https://github.com/google/flutter-desktop-embedding



相关阅读

  • 爱奇艺花式骗钱?被告上法庭的背后

  • 据1月31日的新闻报道,广东一名用户因限制投屏将爱奇艺告上法庭。该用户自称自2017年其就成了爱奇艺会员,会员时长高达7年之久。在之前使用过程中,通过投屏到TV不对清晰度做出限
  • 好雨知时节,雨水已至~

  • 雨水是二十四节气之中的第2个节气于每年公历2月18日至20日交节2023年2月19日我们迎来雨水节气一场场春雨将春日气息渗透万物之间打破冬天的沉寂雨水时节,天气变化不定忽冷忽
  • 宜春的美!释放在春日~

  • 春天迈着优雅的步伐走来了春风一吹花香循着风的踪迹便展开了笑颜一起来看看吧~▼近日航拍樟树市黄土岗镇管王村水田星罗密布,菜花竞相绽放宛如一幅美丽的水乡画卷美不胜收近
  • 价格涨到历史最高!很多人爱吃

  • 夜市的灯火亮了桌椅备齐一盆盆香气四溢的小龙虾便端上了桌个大、肉弹、味绝能讨好你的味蕾算什么这家伙它能让你一扫疲惫忘掉烦恼如果幸福有形状那应该是小龙虾的模样春季到
  • 多所学校因学生发烧停课!疾控中心发布提醒

  • 近日,上海青浦一小学某班级因多名学生发热,停课4天。据媒体消息,青浦区教育局证实此通知属实,并表示学生们患的是甲流,并非新冠。如今正是春季传染病多发季节,甲流、诺如病毒等易
  • 刚刚通报:我国本轮疫情已基本结束

  • 今天(2月23日),国务院联防联控机制举行新闻发布会。梁万年:我国本轮疫情已基本结束,感染零星局部散发疫情走出大流行的标志是什么,又该如何理解“疫情防控重大决定性胜利”?2月23日
  • 全国首例!这一网络平台被叫停

  • 目前随便在网上搜索,都能找到游戏代练App。这种代练平台可以帮助玩家快速提升段位、加速通关。然而代练平台能绕过“防沉迷”系统,允许未成年人自由进入游戏世界。△央视财经
  • 中国稀土集团总部信息化人才招聘公告

  • 中国稀土集团有限公司成立于2021年12月23日,是国务院国有资产监督管理委员会直接监管的大型中央企业。由中国铝业集团有限公司、中国五矿集团有限公司、赣州稀土集团有限公司

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • FlutterEngine 桌面端架构浅析

  • 1 前言在钉钉 Flutter 桌面端落地过程中,我们遇到了很多仅仅依赖 Flutter 官方文档无法解决的问题,例如:桌面端集成模式问题、内存泄露问题、卡顿问题、光标焦点异常问题等。由
  • 干货 | 信息图谱在携程酒店的应用

  • 作者简介 Kuan、Pengfei,主要从事携程酒店知识图谱、问一问智能查询助手、内容信息挖掘平台的建设运维工作,热衷于各类大数据和分布式相关技术的研究和实践。“对于用户的每一
  • 打人赔偿209万之后,来看王思聪的商业版图

  • 没有微博的王思聪,依然是顶流。#王思聪疑打人后行政拘留被暂缓执行#、#王思聪与上海打人的34岁王某某年龄不符#、#权威人士称上海打人者王某某系王思聪#、#传王思聪209万与被
  • 网红小吃身价暴涨,消费者逐渐离场

  • 细数今年比较火的网红小吃,热奶宝、草莓塔、糖炒栗子......他们已经不再走街串巷,而是入住各大商场门店,外卖平台上花里胡哨的造型配上精美的“街拍”图片,逐渐替代了记忆中香甜
  • 卤味江湖,何时才见黑马?

  • 卤味一直是极其具有想象力的行业之一。具有想象力的原因有很多:比如店面较小更好算账、选址也更容易;产品标准化程度高、更易发展规模效益;消费粘性高;中国具有悠久的卤味文化..
  • 爱奇艺花式骗钱?被告上法庭的背后

  • 据1月31日的新闻报道,广东一名用户因限制投屏将爱奇艺告上法庭。该用户自称自2017年其就成了爱奇艺会员,会员时长高达7年之久。在之前使用过程中,通过投屏到TV不对清晰度做出限