2.1 Flutter源码调试
一般情况下,通过flutter run 构建并运行flutter工程时,会生成Engine/Embedder的依赖配置并通过Gradle从云端仓库下载官方已经构建好病上传的构建产物,但是我们也可以自定义参数指定使用本地自己构建的Engine/Embedder产物。Flutter 编译Engine/Embedder见:Flutter源码获取与编译
基于本地构建产物编译Flutter应用
$ ../flutter/bin/flutter run --local-engine-src-path ~/flutter_source/src --local-engine=android_debug_unopt #使用自己的目录
Flutter Framework层调试
Framework层调试,Android Studio本身就是支持的,就不做赘述了。
Flutter Embedder层调试
通过上述的指令(--local-engine-src-path,--local-engine)参数指定自定义的Engine和Embeder构建一个Flutter App,并不能在Android Studio中像Framework那样调试Embedder的Java代码,因为当前项目呗识别为Flutter工程,而非Android工程。如果使用Android Studio直接打开flutter工程下的android目录,则相关的Local Engine参数都没有配置,自然无法被当作源码解析。
对于Embedder的调试,也是可以通过Android项目构建时候增加相关参数,指定使用自己编译后的文件,在src/out/android_debug_unopt中有Embedder的jar文件和pom文件,可以构建自己的本地仓库,代替默认的远程仓库。
但是也可以通过更简单的方式来调试
使用Android Studio 对Embedder源码调试
无论是使用VS Code还是Android Studio都需要上述LLDB的配置准备工作,推荐使用上面的VS Code,因为使用Android Studio的这种方式调试的时候使用的是Engine变异产物的flutter.jar文件
步骤:
- 创建一个Flutter Module工程,命令行创建
../flutter/bin/flutter create -t module flutter_module
- 将上述flutter module打包成aar
../flutter/bin/flutter build aar
- 创建一个常规的Android 工程,将Enfine源码构建出来的flutter.jar文件和上面打包的aar文件复制到libs目录
- 配置app/build.gradle
android {
defaultConfig {
ndk { // 确保加入目标架构的libflutter.so进行构建
abiFilters "armeabi-v7a"
}
}
compileOptions { // Embedder须使用JDK1.8构建
sourceCompatibility 1.8
targetCompatibility 1.8
}
}
dependencies {
implementation files('libs/flutter.jar') // Engine和Embedder源码
implementation files('libs/flutter_debug-1.0.aar') // Framework的构建产物
}
Engine源码调试
对于Engine的调试相对来说就会复杂一些,简单说明下,调试时候,源码在PC端,而代码运行在具体设备(Android/IOS等),那么挑食过程必然有数据通信和通信协议,比如Java代码调试常见的Socket和JDWP,而Engine是基于C++开发,很多步骤要手动完成。此外会准备一个Flutter项目方便后续调试,下面提到的com.lwj.flutter_app是一个Flutter的默认计数器demo项目。
- LLDB调试配置
首先调试器选lldb,简单说明下lldb,Android端调试Native代码一般也使用lldb,在Android Studio SDK Manager界面可以安装lldb(注意: 低版本的Android Studio 可能找不到该选项,高版本的Android studio也有可能找不到该选项,高版本找不到是因为lldb相当于内置了,不需要单独安装,但是不方便外部调用(手动下载戳 LLDB),Android Studio的安装目录和Flutter Engine编译产物的文件夹下都有lldb-server文件,不必纠结Android studio版本和是否可以独立下载 )
lldb示意图
关于lldb远程调试的配置方式参考:LLDB Remote Debugging
(PS:按照上面文档配置后存在一个问题,就是最后挂载进程时,无法关联到我们的flutter应用进程。这个是因为系统权限限制,除非将手机ROOT,否则一直会提示attach fail
那这个问题怎么解决?其实可以将lldb-server添加到需要调试的应用中。通过run-as获取应用权限,进入应用目录下进行操作。注意,使用run-as的应用只能是debug应用,其他应用不可以使用。)
LLDB配置步骤大致如下:
- 确定lldb-文件位置(可手动下载 LLDB,)
# Android studio安装目录下的路径(不确定从那个版本开始内置)
/Applications/Android\ Studio.app/Contents/plugins/android-ndk/resources/lldb/android/armeabi/lldb-server
# Flutter Engine目录下的lldb-server路径
/Users/lwj/Desktop/flutter_source/engine/src/third_party/android_tools/ndk/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/11.0.5/lib/linux/arm/lldb-server
- 找到lldb-server所在目录位置,并将其推送到手机中
我用的是Flutter Engine 编译产物目录下的lldb-server,执行adb命令,将lldb-server push到临时文件夹
adb push /Users/lwj/Desktop/flutter_source/engine/src/third_party/android_tools/ndk/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/11.0.5/lib/linux/arm/lldb-server /data/local/tmp/lldb-server
- 将lldb-server复制到app的私有目录
执行命令如下:
adb shell run-as com.lwj.flutter_app cp -F /data/local/tmp/lldb-server /data/data/com.lwj.flutter_app/lldb-server
- 赋予lldb-server可执行权限
adb shell run-as com.lwj.flutter_app \chmod a+x /data/data/com.lwj.flutter_app/lldb-server
- 启动lldb-server,这样设备就可以接受相应调试命令了
adb shell "run-as com.lwj.flutter_app sh -c '/data/data/com.lwj.flutter_app/lldb-server platform --server --listen unix-abstract:///data/data/com.lwj.flutter_app/debug.socket'"
- 获取待调试应用进程id
先使用自己编译的Flutter Engine启动demo工程
在demo目录下执行命令
flutter run --local-engine-src-path=/Users/lwj/Desktop/flutter_source/engine/src --local-engine=/Users/lwj/Desktop/flutter_source/engine/src/out/android_debug_unopt
执行命令获取pid
adb shell pidof com.lwj.flutter_app
30226
到这里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": "30226", # 上面获取的pid
"initCommands": [
"platform select remote-android",
"platform connect unix-abstract-connect:///data/data/com.lwj.flutter_app/debug.socket"
],
"postRunCommands": [
"add-dsym /Users/lwj/Desktop/flutter_source/engine/src/out/android_debug_unopt/libflutter.so",
"settings set target.source-map /Users/lwj/Desktop/flutter_source/engine/src/out/android_debug_unopt /Users/lwj/Desktop/flutter_source/engine/src/"
]
}
]
}
- 设置断点,F5开始调试。
我将断点打到了 src/flutter/lib/ui/window/window.cc
点击demo的+号,触发断点
断点
参考:
《Flutter内核源码剖析》
Flutter Engine源码调试