Flutter Engine 调试
进行 engine 定制化 ,下载引擎的过程中,需要网络良好,不过失败了,可以继续下载,需要科学上网。
1.depot_tools 安装
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git 配置环境变量:export PATH=$PATH:/path/to/depot_tools
2.源码 Clone (实际这里只是下载一份源码,建议还是从 gitee 下载,这样速度快一些)
- fork Flutter Engine 到自己的 Github 仓库
- 创建引擎存放目录、添加 .gclient 文件
mkdir engine
cd engine
touch .gclient
- gclient 内容如下(替换为自己的 Github Flutter Engine 仓库)
// url 改为自己的仓库( fork 过的)
solutions = [ { "managed": False, "name": "src/flutter", "url": "git@github.com:<YOUR_NAME>/engine.git", "custom_deps": {}, "deps_file": "DEPS", "safesync_url": "", }, ]
- gclient sync
gclient sync
- 同步代码过程较为漫长(总共22G左右),当进度为100%时,依然会下载4~5个G的内容,请不要中断,可以在活动监视器中观察网络使用情况。
3.与官方仓库关联
- 查看当前远程仓库
cd src/flutter
git remote -v
origin git@github.com:<YOUR_NAME>/engine.git (fetch)
origin git@github.com:<YOUR_NAME>/engine.git (push)
- 添加指向官方仓库的 upstream
git remote add upstream git@github.com:flutter/engine.git
- 查看 origin 和 upstream
cd src/flutter
git remote -v
origin <git@github.com>:\<YOUR\_NAME>/engine.git (fetch)
origin <git@github.com>:\<YOUR\_NAME>/engine.git (push)
upstream git@github.com:flutter/engine.git (fetch)
upstream git@github.com:flutter/engine.git (push)
-从原仓库拉取代码并直接合并代码
git pull upstream
- 匹配版本
- 在实际开发中,一般不直接使用 master 的代码直接编译,都是需要获取指定版本的 engine 代码。可以通过本地安装的 Flutter SDK 版本来获取所对应的 engine 版本
fvm global 3.22.2 //切换通道到制定版本
cat dev/flutter/bin/internal/engine.version //获取当前版本commit id edd8546116457bdf1c5bdfb13ecb9463d2bb5ed4
- 切换分支同步代码
cd engine/src/flutter
git reset --hard edd8546116457bdf1c5bdfb13ecb9463d2bb5ed4
//本次 sync 时间较长(本人梯子6-8M/s要等待大概10分钟左右),依然要同步4~5个G的内容,请耐心等待。我的经验是关注活动监视器网络情况,如果收到数据速度小于梯子正常速度,中断后再次执行同步命令即可。
gclient sync -D --with\_branch\_heads --with\_tags -v
5.编译
- 创建编译的工程 (其他参数还可以拼接)
- Android
./flutter/tools/gn --android --unoptimized
./flutter/tools/gn --android --unoptimized --android-cpu=arm64 ./flutter/tools/gn --android --runtime-mode=release
./flutter/tools/gn --android --android-cpu=arm64 --runtime-mode=release
- 查阅其他平台
- 编译引擎
- Android
// 这里编译了多个版本,如果测试学习编译一个也行,这样还快点
// 启动的核心数,最好不要超了 cpu 的核心数
ninja -C out/android_debug_unopt -j 6
ninja -C out/android_debug_unopt_arm64 -j 6
ninja -C out/android_release -j 6
ninja -C out/android_release_arm64 -j 6
- 增量编译
- 各平台首次编译时间较长,大概30-60分钟,以后改动代码后再次编译为增量更新,大大缩短编译时间
6.测试编译后的引擎
- 创建 flutter 应用
flutter create exec_customer_engine
- 在pubspec.yaml文件添加如下依赖
dependency_overrides:
sky_engine:
path: /Users/alan/.fvm/engine/src/out/android_debug_unopt_arm64/gen/dart-pkg/sky_engine
- 添加启动参数
//一定要添加 --local-engine-host ,否则会失败
//--local-engine-src-path 引擎的路径
// --local-engine 引擎的版本
// --local-engine-host 引擎的 host
cd exec_customer_engine flutter run --local-engine-src-path /Users/alan/.fvm/engine/src --local-engine=android_debug_unopt_arm64 --local-engine-host=android_debug_unopt_arm64
- 或将启动参数配置在 IDE 中
- 验证引擎
- 如何验证编译 App 的时候,确实是用了我们自编译的 Flutter Engine 呢?我们可以修改 Flutter Eingine ,加一些日志输出看看。使用 Xcode 打开 engine/src/out/android_debug_unopt_arm64/flutter_engine.xcodeproj 工程文件
然后,打开 代码文件 engine/src/flutter/shell/common/engine.cc 源代码文件。
- 再次编译引擎
ninja -C out/android\_debug\_unopt\_arm64
- 再次使用自编译的引起启动 app ,观察控制台输出
- Engine源码调试
- 对于Engine的调试相对来说就会复杂一些,简单说明下,调试时候,源码在PC端,而代码运行在具体设备(Android/IOS等),那么挑食过程必然有数据通信和通信协议,比如Java代码调试常见的Socket和JDWP,而Engine是基于C++开发,很多步骤要手动完成。此外会准备一个Flutter项目方便后续调试,下面提到的 com.example.exec_customer_engine 是一个Flutter的默认计数器demo项目。
- Engine 源码调 LLDB 配置步骤大致如下
- lldb 位置
// step 1 lldb 位置
/Users/alan/.fvm/engine/src/third\_party/android\_tools/ndk/toolchains/llvm/prebuilt/darwin-x86\_64/lib/clang/17.0.2/lib/linux/aarch64/lldb-server
// step 2 找到lldb-server所在目录位置,并将其推送到手机中 我用的是Flutter Engine 编译产物目录下的lldb-server,执行adb命令,将lldb-server push到临时文件夹
adb push /Users/alan/.fvm/engine/src/third\_party/android\_tools/ndk/toolchains/llvm/prebuilt/darwin-x86\_64/lib/clang/17.0.2/lib/linux/aarch64/lldb-server /data/local/tmp/lldb-server
// step 3 将lldb-server复制到app的私有目录 执行命令如下
adb shell run-as com.example.exec\_customer\_engine cp -F /data/local/tmp/lldb-server /data/data/com.example.exec\_customer\_engine/lldb-server
// step 4 赋予lldb-server可执行权限
adb shell run-as com.example.exec\_customer\_engine \chmod a+x /data/data/com.example.exec\_customer\_engine/lldb-server
// step 5 启动lldb-server,这样设备就可以接受相应调试命令了
adb shell "run-as com.example.exec\_customer\_engine sh -c '/data/data/com.example.exec\_customer\_engine/lldb-server platform --server --listen unix-abstract:///data/data/com.example.exec\_customer\_engine/debug.socket'"
// step 6 获取待调试应用进程id 先使用自己编译的Flutter Engine启动demo工程 在demo目录下执行命令
flutter run --local-engine-src-path /Users/alan/.fvm/engine/src --local-engine=android\_debug\_unopt\_arm64 --local-engine-host=android\_debug\_unopt\_arm64
// step 7 执行命令获取pid
adb shell pidof com.example.exec\_customer\_engine
到这里 LLDB 的配置就完成了,我们可以基于上面的配置,通过 VS Code 断点调试 Flutter Engine 源码
- 使用 VS Code 源码调试
- 使用 VS Code 打开 Engine 所在目录
- 配置 launch.json 文件
{ "version": "0.2.0", "configurations": \[ { "type": "lldb", "request": "attach", "name": "android\_attach", "pid": "16649", "initCommands": \[ "platform select remote-android", "platform connect unix-abstract-connect:///data/data/com.example.exec\_customer\_engine/debug.socket" ], "postRunCommands": \[ "add-dsym /Users/alan/.fvm/engine/src/out/android\_debug\_unopt\_arm64/libflutter.so", "settings set target.source-map /Users/alan/.fvm/engine/src/out/android\_debug\_unopt\_arm64 /Users/alan/.fvm/engine/src/" ] } ] }
- 设置断点,F5 开始调试。 我将断点打到了 src/flutter/lib/ui/text/paragraph.cc 点击 demo 的+号,触发断点
- 参考: