前言
App中使用flutter已经有段时间了,最近遇到一个bug记录一下。更新flutter module工程pubspec plugin依赖,App工程中pod update之后,从功能表现上看依然是老代码。第一感觉是缓存导致的,xcode clean 以及删除DerivedData目录重新build依然不行,flutter module工程中执行flutter clean然后xcode build是正常的,所以应该是dart编译产物有缓存导致的。接下来看下dart编译过程。
编译
1 | cd path/to/flutter module |
进入到flutter module工程目录 执行flutter build ios命令
1 | Running Xcode build... |
可以看到会进行xcode build,进到.ios目录通过xcode打开Runner工程
可以看到build phases中这样一段脚本,这里就是执行dart代码编译的入口。
xcode_backend.sh
进入到脚本所在目录,看下build对应的方法 BuildApp
1 | if [[ $# == 0 ]]; then |
1 | BuildApp() { |
可以看到 ├─Assembling Flutter resources… 在build ios 执行过程中出现过,flutter build bundle 就会开始真正的dart编译
–depfile 指定参与编译的dart文件路径集合
–asset-dir 指定资源产物的目录
flutter命令
路径 $FLUTTER_ROOT/bin/flutter
1 | ... |
flutter_toools.snapshot实际上就是$FLUTTER_ROOT/packages/flutter_tools这个项目编译生成的snapshot文件
所以flutter build bundle 就是使用dart来执行flutter_tools项目的main方法
flutter_tools
路径 $FLUTTER_ROOT/packages/flutter_tools
main方法定义 $FLUTTER_ROOT/packages/flutter_tools/bin/flutter_tools.dart
1 | void main(List<String> args) { |
再看看 lib/executable.dart ,在这里会预先创建好每一种命令对应的对象command,通过解析args参数找到对应的command。在BuildCommand类中
1 | BuildCommand({bool verboseHelp = false}) { |
看到BuildIOSCommand 以及 BuildBundleCommand的创建。
BuildIOSCommand 就是前面提到的flutter build ios 会执行到的,这里我们重点看下BuildBundleCommand是如何编译dart代码的?编译后生成了哪些资源?这些资源都是些什么?
BuildBundleCommand
- app.dill : 这就是dart代码编译后的二级制文件
- Frontend_server.d : 这里面放的是frontend_server.dart.snapshot的绝对路径,使用该snapshot来编译dart代码生成上面的app.dill
- snapshot_blob.bin.d : 这里面放的是所有参与编译的dart文件的绝对路径的集合,包括项目的代码和flutterSdk的代码以及pub库中的三方代码。
- snapshot_blob.bin.d.fingerprint : 这里面放的是snapshot_blob.bin.d中的所有文件的绝对路径以及每个文件所对应的md5值。使用这个md5来判断该文件是否有修改。在每次编译的时候会判断,如果没有文件修改,则直接跳过编译。
编译Dart资源
1 | Future<void> build({ |
编译Dart代码
1 | class KernelCompiler { |
Fingerprint对比
1 | Future<bool> doesFingerprintMatch() async { |
重点 看看 newFingerprint
1 | Future<Fingerprint> buildFingerprint() async { |
可以看到newFingerprint 路径依旧是使用缓存的路径,依次计算路径对应文件的md5,所以问题就在这里了
执行flutter packages upgrade更新pub依赖的时候,build目录下的缓存产物并不会有任何变动,路径依然是老的路径。有一种情况就是module工程 lib 目录下的dat文件有改动,newFingerprint就会跟old不一样,这会重新编译dart,这里又有一个问题,就是如果lib目录下是新增dart文件 则不会被编译进去。
最后
综上,执行flutter clean命令,清空build目录缓存文件,build ios 就会重新编译整个dart文件,包括pub依赖中的。