前语
作为开发iOS
的一名程序员,大环境不好了,学点Flutter
吧。今天咱们从布景常识,Flutter
引擎编译,Flutter
引擎验证调试,Flutter
引擎运用等方面来研究下Flutter
引擎
布景常识
Flutter
是一个跨渠道的UI
东西集,它的规划初衷,就是答应在各种操作系统上复用
相同的代码。
在开发中,Flutter
运用会在一个 VM
(程序虚拟机)中运转,然后能够在保存状况且无需从头编译的情况下,热重载相关的更新
架构层
Flutter
引擎 毫无疑问是 Flutter
的中心,它主要运用 C++
编写,并供给了 Flutter
运用所需的原语
。当需求绘制新一帧的内容时,引擎将担任对需求组成的场景进行栅格化
。它供给了 Flutter
中心 API
的底层完成,包含图形(在 iOS
和 Android
上经过 Impeller
,在其他渠道上经过 Skia
)、文本布局、文件及网络 IO
、辅助功用支持、插件架构和 Dart
运转环境及编译环境的东西链。
引擎将底层 C++
代码包装成 Dart
代码,经过 dart:ui
露出给 Flutter
结构层。该库露出了最底层的原语,包含用于驱动输入、图形、和文本烘托的子系统的类。
通常,开发者能够经过 Flutter
结构层 与 Flutter
交互,该结构供给了以 Dart
言语编写的现代呼应式结构。它包含由一系列层组成的一组丰富的渠道,布局和根底库。从下层到上层,顺次有:
-
根底的
foundational
类及一些底层之上的构建块服务,如animation
、painting
和gestures
,它们能够供给上层常用的笼统。 -
烘托层 用于供给操作布局的笼统。有了烘托层,你能够构建一棵可烘托目标的树。在你动态更新这些目标时,烘托树也会自动依据你的改变来更新布局。
-
widget
层 是一种组合的笼统。每一个烘托层中的烘托目标,都在widgets
层中有一个对应的类。此外,widgets
层让你能够自由组合你需求复用的各种类。呼应式编程模型就在该层级中被引进。 -
Material
和Cupertino
库供给了全面的widgets
层的原语组合,这套组合分别完成了Material
和iOS
规划规范。
运用分析
下图为你展现了一个经过flutter create
指令创立的运用的结构概览。该图展现了引擎在架构中的定位,突出展现了 API
的操作鸿沟,并且标识出了每一个组成部分
DartApp
咱们写的dart
代码,一般在/lib
目录下
- 将 widget 组成预期的 UI。
- 完成对应的业务。
- 由运用开发者进行办理。
Framwork
坐落Flutter SDK
的flutter/packages/flutter/lib/src
途径下
- 供给了上层的 API 封装,用于构建高质量的运用(例如 widget、触摸检测、手势竞技、无障碍和文字输入)。
- 将运用的 widget 树构建至一个 Scene 中。
engin
Flutter SDK
的引擎在flutter/bin/cache/artifacts/engine
途径下
- 将已经组成的 Scene 进行栅格化。
- 对 Flutter 的中心 API 进行了底层封装(例如图形图像、文本布局和 Dart 的运转时)
- 将其功用经过dart:ui API露出给结构。
- 运用嵌入层 API与渠道进行整合。
引擎的源码对应的途径在engin/src/flutter/shell/common
下
embedder
embedder
对应的带源码途径在engin/src/flutter/shell/platform/embedder
下
- 和谐底层操作系统的服务,例如烘托层、无障碍和输入。
- 办理工作循环系统。
- 将特定渠道的 API露出给运用集成嵌入层。
Runner
对应各个渠道的宿主APP
- 将嵌入层露出的渠道 API 组成为目标渠道能够运转的运用包。
- 部分内容由
flutter create
生成,由运用开发者进行办理。
编译引擎
装备depot_tools
Chromium
运用了depot_tools
来办理代码,获取 depot_tools
源码前,需敞开 VPN
服务,科学上网
- Git拉取代码
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH="$PATH:$HOME/depot_tools"
新建目录
mkdir engine
途径上最好不要带中文,否则后续下载编译运转引擎代码或许会有奇奇怪怪的报错
装备gclient文件
cd engine
touch .gclient
文件内容如下:
solutions = [ {
"managed": False, "
name": "src/flutter",
"url": "git@github.com:flutter/engine.git@360ca05311c8fafe73333ca2c58dfecf9b701d40",
"custom_deps": {},
"deps_file": "DEPS",
"safesync_url": "", }, ]
其间360ca05311c8fafe73333ca2c58dfecf9b701d40
是commitId,查找方法如下:
-
flutter --version
查看flutter
版别,笔者这边是3.10.6
- 翻开github.com/flutter/eng…
- 搜索找到
flutter-3.10-candidate.6
的分支 - 复制最新的commitId
过程中需求留意的是:引擎产品跟flutter
的sdk
版别是一一对应的,所以咱们挑选stable
的版别,代码基本不会变,这样相对稳定点,不必经常编译
同步代码
gclient sync
这个操作是个耗时操作,需求科学上网,过程中会下载Flutter
一切的依赖,执行完能够做其他工作,慢慢等着就好了,大概有10来G
的文件
SDK晋级
咱们知道SDK版别跟引擎是一一对应的,晋级了SDK怎样晋级引擎呢
- 咱们先找到SDK下的
flutter/bin/internal/engine.version
,里边有对应的commitId
- 到
.gclient
⽂件修正对用的commitId
- 然后到
src/flutter
下
git pull
git reset --hard commitID
- 回到
engine
⽬录,也就是.gclient
⽂件所在的⽬录
$gclient sync --with_branch_heads --with_tags --verbose
运用GN东西生成
GN
这个东西是一个生成Ninja
构建文件的元构建
系统,找到它的途径如下:
运用如下指令生成Ninja
构建文件
#构建iOS设备使⽤的引擎
#真机debug版别
./gn --ios --unoptimized
#真机release版别(⽇常开发使⽤,假如咱们要⾃定义引擎)
./gn --ios --unoptimized --runtime-mode=release
#模拟器版别
./gn --ios --simulator --unoptimized
#主机端(Mac)构建
./gn --unoptimized
得到的4个Xcode工程如下:
过程中笔者出现以下报错:
咱们有爱好能够参看 github.com/flutter/flu… 装备goma
环境
笔者这儿直接运用了--no-goma
的flag
,也顺利构建了
运用Ninja编译工程
ninja -C host_debug_unopt && ninja -C ios_debug_sim_unopt && ninja -C ios_debug_unopt && ninja -C ios_release_unopt
这也是个耗时操作,笔者这儿编译了4个,也能够依据自己的需求只编译自己需求的部分工程
编译完的四个引擎也要进30个G
了
编译后的产品:
至此flutter
引擎编译部分到此就完毕了
能够运用lipo -info xxx
来查看产品的架构信息
运用引擎
装备工程
指令行新建flutter
工程, 翻开iOS
工程,找到Generated.xcconfig
文件,最终加上如下两行:
FLUTTER_ENGINE=你寄存引擎代码的途径/engine/src
#使⽤的引擎对应版别(这⾥是iOS-debug形式下-真机的版别)
LOCAL_ENGINE=ios_debug_unopt
验证引擎代码是否收效
翻开引擎代码工程,找到engine.cc
文件
修正Engine::RunStatus Engine::Run(RunConfiguration configuration)
这个函数
参加一些自定义的代码
运转iOS
工程,咱们奇怪的发现控制台并没有打印咱们自定义的文案,这是怎样回事呢?
咱们加下断点发现函数是能进来的
原来呀引擎代码修正也是要从头编译的,咱们在跑下ninja
编译指令
这次只要编译16个文件
,所以速度比较快的,编译完代码再次运转iOS工程
这次终于打印了咱们自定义的代码,这就验证了咱们编译的引擎收效了!
调试引擎代码
咱们在上面验证的过程中其实已经用到了断点的功用,没有断点断住的小伙伴看这儿怎样调试代码
找到对应渠道编译的产品下对应的flutter_engine_xcodeproj
工程拖入咱们自己的iOS工程中
拖进去后
接着就能够随意断点
了
调试引擎代码就到此,要是还没调试成功的小伙伴查看下Generated.xcconfig
这个文件里装备的途径对不对,然后最终途径上不要有中文
(或许会有问题)。别的假如是Mac
工程的话需求装备的文件是Flutter-Generated.xcconfig
实践用途
调试学习
第一个用途当然是断点调试源码
了,不要太爽了,当然源码太多,一般学到什么功用再进行深入调试比较好
魔改引擎代码
Flutter
源码是支持动态化
的,能够经过魔改Flutter
引擎完成动态化。当然dart
自身是支持放射
的,可是flutter
禁用了dart
的放射
功用,否则也会被封杀吧。魔改引擎代码其实成本还蛮大的,一般公司慎用!
处理具体问题,比方内存问题
时间线回到22年6月
前,来看下这个issue:iOS指针紧缩形成的OOM
其时的处理方案能够等官方更新SDK
,不过假如用户反馈比较多来不及等更新,只能改gn代码
:
找到gn
方位
做相似这样的改动
总结
- Flutter运用能够分析为DartApp,Framwork,Engin,Embedder,Runner,前三层是渠道无关的,后两层是渠道相关的
- 编译引擎:
- 装备depot_tools
- 装备gclient文件,留意commitId
- gclient sync同步代码
- SDK晋级修正对应commitId,从头sync
- 运用GN东西生成构建Ninja构建文件
- 运用Ninja编译工程
- 验证引擎:
- 修正代码留意从头编译,查看引擎途径
- 调试引擎代码:
- 拖进xcode工程断点调试
- 实践用途:
- 调试学习
- 动态化
- 处理具体问题,比方内存问题