2025 Flutter Engine Source Setup
我的学习笔记以及感悟还有一些小坑,仅供参考~ 北京有岗位内推的练习我啊~~~🤣
Fltter 开发团队的核心成员大都有Chromium项目工作经验,所以在Flutter源码获取的过程中,都或多或少的看到Chromium的影子。

Flutter在软件设计上是一个可灵活扩展的分层架构,每个组件功能都是以库的形式存在,每个库都依赖下一层的库。
这样设计的好处是让框架的每一个组件都变得可插拔、可替换。作为一个跨平台框架,对服用和移植到其它平台非常合适。
💡
插入一个题外话~看到这张图,是不是有中似曾相似的感觉,在看《Android的第一行代码》《UNIX编程艺术》等,甚至OSI七层模型,相信其他系统在书本中也有类似架构,和Flutter的分层架构设计大同小异。在《UNIX编程艺术》对这种设计有一个贴切的称呼:**正交性。由于正交性存在,OSI模型才会有各种协议(如运输层的TCP UDP) **
自底向上的简要分析下每一层:
Embedder:
Embedder顾名思义,将Flutter嵌入到Native平台,如iOS,Android, Windows ,Linux,所以每个平台上,都会包含一个特定的嵌入层。它的职责是渲染UI到Surface【一块可以被GPU渲染显示到区域,FlutterUI渲染最终都会输出到Surface上,Embedder负责创建和管理Surface,不同平台实现方式不同,Flutter Engine通过Skia绘制UI到Surface,然后由操作系统合成并显示到屏幕上】、处理单机事件等与底层平台交互行为提供一个入口。Embedder使用的编程语言与特定平台有关,比如Android 使用Java和C++, iOS 和 macOS 使用 Swift 和 Objective-C/Objective-C++,Windows 和 Linux 则使用 C++。
Engine:
Flutter的核心部分,大部分代码是C++,包装成Dart代码,这个库是最底层的原语 主要职责是图形绘制,文字渲染,文件/玩过IO,无障碍支持,平台插件,Dart运行时管理和编译器工具链等。主要通过dart:ui暴露给Flutter框架层进行双向交互。
Framework:
通常我们只需要关注Framework层。这一层由Dart语言开发。提供现代、响应式的UI框架。这一层也是分层的。
**Foundation & Animation & Painting & Gestures: **
提供公用底层能力,对engine的抽象和封装
**Render: **
主要负责Render Tree的Layout操作等,最终将绘制指令发送给Engine进行绘制。通过这一层,可以构建一个可渲染对象的树结构==》 Render Tree。
**Widgets: **
对上一层Render的上层分装,Render Tree虽然能够决定最终UI,但是过于复杂,不适合开发使用,Widgets则通过组合思想,提供了丰富的widgets组件,供开发者使用。 Render层中每个渲染对象在这一层都有对应的类。wigets层可以自由组合需要复用的类,这一层引入了响应式编程Reactive Programming。
**Material & Cupertino: **
这俩个组件是针对Widgets进一步封装,Widgets对于开发者来说还是很原始,这俩个组件是基于iOS和Android设计规范提供了更完备的组件,保证开发者开箱即用。
应用剖析
简单分析 flutter create 命令创建的应用结构概览,展示了 Flutter 引擎在此技术栈中的位置,标明了 API 边界,并注明了各组件所在的代码库。下方图例阐释了描述 Flutter 应用组件时常用的术语。
Dart App:
开发者自己写的UI&业务逻辑代码,使用FrameworkSDK提供的Widgets构建UI。
Owned by app developer.
一般说的是工程内****lib/** **下的代码
Framework 框架:
提供了上层API封装,构建高质量应用,例如( widget、触摸检测、手势竞技、无障碍和文字输入)。
将开发者的应用的Widgets树构建至一个Scene中,传递给下层Engine的skia处理,再传递给对应的平台
就是我们安装的SDK,**flutter/packages/flutter/lib/ **
Engine:
-
将上层传递过来的Scene 栅格化
-
对Flutter的核心API进行了底层封装(如图形图像,文本布局,Dart运行时)
-
将其功能通过dart:ui暴露给上层Framework
-
使用引擎的 Embedder API 与特定平台集成。
我们平时用到的engine都是编译好的引擎产物,位置在这里****flutter/bin/cache/artifacts/engine/ios/** **
我这里看的iOS平台的Engine框架,这里有好多平台的,MacOS 、Android。
点个模拟器平台的看一下:
用 烂苹果 看一下:
模拟器提供了俩个架构的,用file命令也可以看
看下下载的引擎源码:
红框的都属于引擎源码
Embedder:
-
与底层操作系统协调,获取渲染表面、无障碍功能和输入等服务。
-
管理事件循环。
-
暴露平台特定 API,将嵌入器集成到应用中。
对应Engine源码中Embedder位置:
Runner:
-
将嵌入器(Embedder)提供的平台特定 API 组件整合成可在目标平台上运行的应用程序包。
-
由
flutter create
生成的应用程序模板的一部分,归应用程序开发者所有。 -
对应各个平台宿主的App
开始编译Engine
**温馨提示:在开始前,最好提前把VPN连着。 **
准备环境
要编译环境,直接从github上下载Flutter和Engine这俩个仓库是不不能构建的,因为Engine和Flutter它俩本身还依赖了很多第三方库,定义在engine根目录的DEPS文件中。
打开这个文件看一下,第一句就描述了这个文件作用
depot_tools工具下载
准备一个文件夹 ,mkdir flutter_source
创建一个空文件夹
bash
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=/path/to/depot_tools:$PATH
-
克隆下载
-
配置环境变量
cd flutter_source 转到这个目录下:
把这个depot_tools 工具克隆在这里, 再配置下环境变量就可以用了**
配置.gclient文件
bash
solutions = [
{
"managed": False,
"name": "src/flutter",
"url": "[email protected]:flutter/engine.git",
"custom_deps": {},
"deps_file": "DEPS",
"safesync_url": "",
},
]
-
name指定仓库位置
-
url 指定要下载的仓库
-
dep_file 指定存放第三方依赖的文件名
执行gclient sync
在当前目录执行这个命令,等待下载engine以及它的依赖。执行完得等待一会,可以通过系统监视器查看当前网络状态,判断gclient执行是否正常。
在终端输出 " Syncing projects: 100%。 done"
后还会启动cipd_client下载部分大文件,直至完成。**
clone Flutter代码仓库
最后文件夹就是这些文件
-
depot工具
-
engineplay
是一个flutter工程 -
flutter 是framework sdk
-
src里就是
.gclient
文件配置的engine源码下载路径
匹配Engine和FlutterSDK版本
Engine是没有版本概念的,但它的CommitID可以在Flutter里看到
我当前的Flutter SDK版本对应的engine是
通过 flutter ---version
也可以看到
gclient sync
**找到了这个CommitID号后,进入src/flutter目录执行 **git checkout 83bacfc525**
, 把代码库恢复到这个提交,就和这个版本对应上了。 之后就可以编译了。 **
都准备好后,在 ****** **src/flutter**
这个目录执行 **gclient sync ---with_branch_heads ---with_tags**
, **这是因为在切换提交的时候,可能DEPS可能发生改变。每次切换后都要进行同步操作。后面俩个参数表示将tag、refspecs等仓库信息一起同步。
💡
⚠️ 注意: 这里有一个坑点, 我看的好多资料,都是比较老的,我下载最新sdk 3.29.1 ,对应的Commit号:871f65ac1bf129edb222c3293a636ff4b67534a6,可能在engine源码里切换找不到这个commiID, 我猜想可能没同步, 之后会延迟FlutterSDK同步,所以我用了3.27版本。不知道之前有没有人遇到过这个。
构建准备
Flutter引擎的源码是需要通过Ninja来编译的,所以需要系统提前装好Ninja,通过brew一键安装。
而gn工具是一个生成Ninja编译所需的构建文件的元文件。
引擎部分大部分都是由C++代码组成,最终的机器码和运行平台与CPU架构是强相关的。对于不同平台,Embedder也有所不同。但是Futter已经借助Chromium工程的GN和Ninja工具链大大简化了这个构建过程。
在src目录下,需要用到这个命令 ****** **./flutter/tools/gn
** ** 命令,需要加上路径,因为前边设置的depot_tools里也有gn命令。这里注意下就可以**
--runtime-mode {debug,profile,release,jit_release}
构建产物的类型,
-
debug日常开发,基于DartVM运行,性能较低。
-
profile 性能测试 release 正式发布 俩者都是编译成机器码,性能较高
-
--target-os {android,ios,mac,linux,fuchsia,wasm,win}
构建产物运行平台,对于Android和iOS还可以通过---android
和---ios
指定。 -
--android-cpu {arm,x64,x86,arm64}
Android产物所属的架构,通常x86用于pc模拟器,其它三种用于真机。
构建iOS产物
准备设备端可执行文件的构建文件 ./flutter/tools/gn --ios --unoptimized
bash
# 1. device-side executables 设备端可执行文件的构建文件
# 输出 out/ios_debug_unopt/flutter_engine.xcodeproj
./flutter/tools/gn --ios --unoptimized # 真机debug版本
./flutter/tools/gn --ios --unoptimized --runtime-mode=release # 真机release版本(日常开发使用,如果我们要自定义引擎)
# 这句是为模拟器生成元件 输出 out/ios_debug_sim_unopt_arm64
./flutter/tools/gn --ios --simulator --unoptimized --simulator-cpu=arm64 #模拟器版本
# 2. host-side executables 主机端可执行文件准备构建文件
# 输出 host_debug_unopt_arm64
./flutter/tools/gn --unoptimized --mac-cpu arm64 # 主机端(Mac)构建
# 3.
ninja -C out/ios_debug_unopt && ninja -C out/host_debug_unopt
ninja -C host_debug_unopt && ninja -C ios_debug_sim_unopt && ninja -C ios_debug_unopt && ninja -C ios_release_unopt
这是我们生成的准备元件,执行完第3行ninja -C
,接下来就是漫长的等待了。
引擎调试
首先启动一个flutter工程,flutter sdk版本指定本地
通过命令行指定编译好的engine
bash
cd engineplay
flutter run --local-engine-src-path engine/src --local-engine=ios_debug_sim_unopt --local-engine-host host_debug_unopt_arm64
也可以在AS参数里指定
然后打开引擎源代码:
在这加一句输出
接着在AS跑个代码【前提AS配置好了自定义引擎】
说明这个工程现在依赖的是我本地编译好的引擎代码。
接下来在Xcode跑一下:
不依赖AS,直接打开项目的Runner。
在xcode里可以自由调试~~ 待写