Flutter - 引擎调试(iOS篇)🛠
# 一、depot_tools
depot_tools (opens new window) 是调试
Flutter
引擎的必备工具包,包含了gclient
、gn
和ninja
等工具,这些在下面会用到!
拉取 depot_tools
到本地,我一般是放到 ~/developer/
下
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
将 depot_tools
的路径补充到 PATH
$ export PATH=/path/to/depot_tools:$PATH
# 如: export PATH=~/developer/depot_tools:$PATH
# 二、配置.gclient
创建 engine
目录,且终端进入到该目录,生成并配置 .gclient
文件
➜ ~ cd /Users/lxf/Desktop/LXF/engine
➜ engine touch .gclient
➜ engine vim .gclient
配置内容:
solutions = [
{
"managed": False,
"name": "src/flutter",
"url": "git@github.com:flutter/engine.git@1837b5be5f0f1376a1ccf383950e83a80177fb4e",
"custom_deps": {},
"deps_file": "DEPS",
"safesync_url": "",
},
]
如果你是仅调试,那链接可以用 flutter
的,但如果你想后面提 PR
,则需要使用自己 fork
后的链接,如:git@github.com:LinXunFeng/engine.git
引擎 git
地址后面携带的 commit id
最好与当前 Flutter
所使用的引擎版本保持一致,可以通过如下命令获取
flutter --version
输出:
Flutter 3.7.7 • channel stable •
...
Engine • revision 1837b5be5f
...
或者取如下文件里的值
flutter/bin/internal/engine.version
# 1837b5be5f0f1376a1ccf383950e83a80177fb4e
# 三、拉取源码
使用终端,进行到 .gclient
所在目录,即上面创建的 engine
目录,执行如下命令
gclient sync
注:gclient
命令来自于 depot_tools
然后坐等完成即可,如果失败了就反复执行 gclient sync
直到成功,大概近10个G
➜ engine gclient sync
Updating depot_tools...
using /var/folders/36/n74_k53x5h5fz70gkd3jr5p00000gn/T/goma_lxf as tmpdir
INFO: creating cache dir (/var/folders/36/n74_k53x5h5fz70gkd3jr5p00000gn/T/goma_lxf/goma_cache).
compiler_proxy is not running
________ running 'git -c core.deltaBaseCacheLimit=2g clone --no-checkout --progress git@github.com:flutter/engine.git /Users/lxf/Desktop/LXF/engine/src/_gclient_flutter_t0dh3d3h' in '/Users/lxf/Desktop/LXF/engine'
Cloning into '/Users/lxf/Desktop/LXF/engine/src/_gclient_flutter_t0dh3d3h'...
remote: Enumerating objects: 326233, done.
remote: Counting objects: 100% (42/42), done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 326233 (delta 11), reused 8 (delta 2), pack-reused 326191
Receiving objects: 100% (326233/326233), 394.55 MiB | 3.88 MiB/s, done.
Resolving deltas: 100% (242690/242690), done.
30>WARNING: subprocess '"git" "-c" "core.deltaBaseCacheLimit=2g" "fetch" "origin" "d40d15e994ed60d32bcfc9ab87004dfb028dfbd6" "--no-tags"' in /Users/lxf/Desktop/LXF/engine/src/third_party/harfbuzz failed; will retry after a short nap...
Syncing projects: 100% (134/134), done.
Hook 'python3 src/flutter/tools/pub_get_offline.py' took 19.13 secs
Running hooks: 100% (11/11), done.
➜ engine
拉取完成后你可以进入 src/flutter
查看当前下载下来的 engine
的 commit id
➜ cd /Users/lxf/Desktop/LXF/engine/src/flutter
➜ flutter git:(1837b5be5f)
如果你的终端没有显示 git:(commit id)
,那可以使用如下命令进行查看
git rev-parse HEAD
# 1837b5be5f0f1376a1ccf383950e83a80177fb4e
# 四、编译
进入 tools
目录,执行几条 gn
命令
➜ cd engine/src/flutter/tools
生成 iOS
设备端可执行文件所需的构建文件
➜ tools git:(1837b5be5f) ./gn --ios --unoptimized
GOMA usage was specified but can't be found, falling back to local builds. Set the GOMA_DIR environment variable to fix GOMA.
Generating GN files in: out/ios_debug_unopt
Generating Xcode projects took 211ms
Generating compile_commands took 55ms
Done. Made 801 targets from 274 files in 6165ms
如果你想调试模拟器,则加上 --simulator
gn --ios --simulator --unoptimized
生成主机端可执行文件所需的构建文件
➜ tools git:(1837b5be5f) ./gn --unoptimized
GOMA usage was specified but can't be found, falling back to local builds. Set the GOMA_DIR environment variable to fix GOMA.
Using prebuilt Dart SDK binary. If you are editing Dart sources and wish to compile the Dart SDK, set `--no-prebuilt-dart-sdk`.
Generating GN files in: out/host_debug_unopt
Generating Xcode projects took 273ms
Generating compile_commands took 70ms
Done. Made 1110 targets from 340 files in 46800ms
执行完成之后,在 engine/src/out
目录下就会多出相应端的构建文件目录
接下来使用 Ninja
进行编译
ninja -C host_debug_unopt && ninja -C ios_debug_unopt
如果你是用 M1/M2
电脑去编译旧引擎源码,可能会在编译 ios_debug_unopt
时遇到如下错误
ninja: Entering directory `host_debug_unopt'
ninja: no work to do.
ninja: Entering directory `ios_debug_unopt'
[13/369] ACTION //flutter/lib/snapshot:create_arm_gen_snapshot(//build/toolchain/mac:ios_clang_arm)
FAILED: clang_x64/gen_snapshot_arm64
python3 ../../flutter/sky/tools/create_macos_gen_snapshots.py --dst /Users/lxf/Desktop/LXF/engine/src/out/ios_debug_unopt/clang_x64 --arm64-out-dir /Users/lxf/Desktop/LXF/engine/src/out/ios_debug_unopt
Cannot find gen_snapshot at /Users/lxf/Desktop/LXF/engine/src/out/ios_debug_unopt/clang_x64/gen_snapshot
[16/369] LINK clang_arm64/impellerc
ninja: build stopped: subcommand failed.
这时你只需要进入到 engine/src/out/ios_debug_unopt
目录下,将 clang_arm64
目录中的 gen_snapshot
拷贝到 clang_x64
,然后再继续执行 ninja -C ios_debug_unopt
即可。
这里强调一下:
- 如果你修改了引擎的源代码,需要重新执行相应的
ninja
命令,如调试引擎时我们会修改代码,如果不执行ninja
命令,你会发现断点修改的代码其它是旧代码! - 如果是新增或删除文件,则需要先执行
gn
命令,再执行ninja
命令。 - 我建议直接
gn
和ninja
命令一起执行,不用管什么情况,脚本会自己检查是否有文件变更,以及是否需要重新生成相应的文件的。
# 五、调试
打开你的Flutter
项目,IDE
以 VSCode
为例,添加 --local-engine-src-path
和 --local-engine
两个参数,完整配置如下
{
"name": "flutter_demo",
"request": "launch",
"type": "dart",
"args": [
"--local-engine-src-path",
"/Users/lxf/Desktop/LXF/engine/src",
"--local-engine",
"ios_debug_unopt"
]
},
参数 | 值 |
---|---|
--local-engine-src-path | 固定为引擎的 src 路径 |
--local-engine | 真机: ios_debug_unopt 模拟器: ios_debug_sim_unopt |
按 F5
跑一遍就可以使用指定引擎运行 Flutter
项目了。
细心的你可能会发现在 flutter_demo/ios/Flutter/Generated.xcconfig
配置文件内新增相应的两个环境变量
...
FLUTTER_ENGINE=/Users/lxf/Desktop/LXF/engine/src
LOCAL_ENGINE=ios_debug_unopt
...
如果我们要调试引擎代码,请打开你的 Runner.xcworkspace
,然后将 flutter_engine
拖入项目
找到 FlutterViewController.mm
给 touchesBegan
打个断点,再运行项目,点击屏幕就会进入到断点处,现在就可以开始愉快的调试 flutter_engine
了
如果你的断点不生效,那请先检查 Generated.xcconfig
里的 FLUTTER_ENGINE
和 LOCAL_ENGINE
变量。
到这里,引擎的编译调试就介绍完毕了。
下一篇,我们来详细说说怎么给 Flutter
引擎提交 PR
🤠
# 六、资料
- 01
- Flutter - 子部件任意位置观察滚动数据11-24
- 02
- Flutter - 危!3.24版本苹果审核被拒!11-13
- 03
- Flutter - 轻松搞定炫酷视差(Parallax)效果09-21