前言
flutter tools中集成了很多强大的命令,比如:
- flutter create: 创建app、module、plugin、package
- flutter build: 构建apk、aar等
- flutter run: 运行 要想弄清楚各种命令背后的原理,一方面可以看静态代码,另一方面则是动态调试。
导入flutter tools源码
我们知道flutter tools是用dart实现的,其源码位于path/to/flutter/packages/flutter_tools。 用Android Studio打开该项目。
设置断点
很多程序的调试原理都类似,都是通过在启动对应的程序时,传入一些调试相关的参数,让对应的进程启动后进行等待,等到Debugger进程attach到该进程后继续运行。
Flutter Tools本质上是一个dart程序,它的调试是Dart虚拟机支持的。
具体到Android Studio上,有两种配置方式:
- Dart Command Line App
- Dart Remote Debug
Dart Command Line App
这一种比较简单,新建一个Dart Command Line App的Configuration。
Edit Configurations -》New -》 Dart Command Line App。如果所示:

Dart file指向flutter_tools.dart,这是入口文件。 Programma arguments填上要运行的命令,比如 create flutter_app. 然后在其中的main方法上添加断点,然后点击调试按钮,如图所示


Dart Remote Debug
新建一个Configuration。 Edit Configurations -》New -》 Dart Remote Debug -》 输入Host为127.0.0.1,端口号为12345,如果所示:

--enable-vm-service:12345 --pause_isolates_on_start来启动dart虚拟机。这两个参数是告诉Dart虚拟机开启调试端口12345,并在启动后暂停等待。
我们可以通过设置FLUTTER_TOOL_ARGS环境变量来设置参数
export FLUTTER_TOOL_ARGS="--enable-vm-service:12345 --pause_isolates_on_start"
然后运行flutter命令
flutter create flutter_app
此时会输出如下信息:
Observatory listening on http://127.0.0.1:12345/-7kH8m0Z5Ys=/
同样设好断点,然后点击调试按钮,结果却发现attach不上,错误信息如图所示
Failed to connect to the VM observatory service: java.io.IOException: Failed to connect: ws://127.0.0.1:12345/ws
Caused by: de.roderick.weberknecht.WebSocketException: error while creating socket to ws://127.0.0.1:12345/ws
Caused by: java.net.ConnectException: Connection refused (Connection refused)
发现url对不上,Dart虚拟机等待的url后面多了个-7kH8m0Z5Ys=
经过查资料,发现这是一种认证码,是为了安全原因,防止应用被远程调试。可以通过参数--disable-service-auth-codes进行关闭。
export FLUTTER_TOOL_ARGS="--enable-vm-service:12345 --pause_isolates_on_start --disable-service-auth-codes"
然后重新运行flutter create flutter_app命令,这次成功了,如图所示

除了通过FLUTTER_TOOL_ARGS环境变量,还可以直接运行dart命令。
dart --enable-vm-service:12345 --pause_isolates_on_start --disable-service-auth-codes /Users/szw/dev_tools/flutter/packages/flutter_tools/bin/flutter_tools.dart create flutter_app
其实FLUTTER_TOOL_ARGS也是flutter命令传给dart的。 flutter脚本的路径为flutter/bin/flutter,其中的最后一行就是
"$DART" --packages="$FLUTTER_TOOLS_DIR/.packages" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"
总结
本文提到的方法不止适用于flutter tools,也适用于其他的dart应用。另外其他语言的调试基本也都类似,大家可以举一反三。