在对 flutter module 进行修改的时候,不知道为何,会发现 .android 目录下和 .ios 目录下的文件会被修改覆盖掉;后来发现,只要咱们变更 pubspec.yaml
的文件, 而后执行命令 flutter packages get
,就会从新从flutter 模板中替换 .android
和.ios
目录; 由于咱们的 .android
目录下有本身定义 gradle 脚本(主要为了解决打包aar的问题);就不但愿这个 gradle 被覆盖;android
flutter packages get
背后的逻辑,经过修改逻辑代码,不去覆盖现有的代码;全部的模板目录都在Flutter_HOME/packages/flutter_tools/templates
下面:ios
以上红色箭头的地方,是我替换和添加的模板代码;ios 应该也能够找到相应的模板进行添加和修改;git
由于是 flutter 命令因此咱们能够去看下 flutter 命令的源码;用文本编辑器打开编辑 FLUTTER_HOME/bin/flutter 文件;最后一行;shell
"$DART" --packages="$FLUTTER_TOOLS_DIR/.packages" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"
复制代码
为了方便观察打印(echo)一下这个命令:数组
echo "$DART" --packages="$FLUTTER_TOOLS_DIR/.packages" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"
复制代码
执行命令 flutter --no-color packages get
获得以下:缓存
/Users/xxxx/flutter/bin/cache/dart-sdk/bin/dart --packages=/Users/xxxx/flutter/packages/flutter_tools/.packages /Users/xxxx/flutter/bin/cache/flutter_tools.snapshot --no-color packages get
复制代码
很明显他是根据 flutter_tools.snapshot
这个文件进行执行的;参数是 --no-color packages get
; 那么 flutter_tools.snapshot
这个二进制文件是怎么生成的呢?markdown
能够继续查看一下 bin/flutter
这个文件;app
"$DART" $FLUTTER_TOOL_ARGS --snapshot="$SNAPSHOT_PATH" --packages="$FLUTTER_TOOLS_DIR/.packages" "$SCRIPT_PATH"
复制代码
这个命令主要是用来编译flutter_tools.snapshot
的,咱们能够打印(echo)一下这个命令; 修改一下 shell 脚本,让它进入 if 语句(怎么修改能够看下第3
段)里面;打印出来的结果以下;async
/Users/xxxx/flutter/bin/cache/dart-sdk/bin/dart --snapshot=/Users/xxxx/flutter/bin/cache/flutter_tools.snapshot --packages=/Users/xxx/flutter/packages/flutter_tools/.packages /Users/xxxx/flutter/packages/flutter_tools/bin/flutter_tools.dart
复制代码
从上面的命令咱们能够看出来全部的源码主要了来自 /Users/xxxx/flutter/packages/flutter_tools
这里目录里面,进去看一下,都是dart 源码;编辑器
if [[
! -f "$SNAPSHOT_PATH"
|| ! -s "$STAMP_PATH"
|| "$(cat "$STAMP_PATH")" != "$revision"
|| "$FLUTTER_TOOLS_DIR/pubspec.yaml" -nt "$FLUTTER_TOOLS_DIR/pubspec.lock"
]]; then
echo Building flutter tool...
fi
复制代码
从上面来看,只要知足这里4个条件其中一个,就会去编译 flutter_tools 生成一个 flutter_tools.snapshot
;
git rev-parse HEAD
pubspec.yaml
文件最后修改时间大于pubspec.lock
文件 (nt: new then)通过以上3 点,接下来,咱们能够去看下 flutter_tools 的源码了;
咱们把源码导入 Android studio 查看更加方便;main 方法从 flutter_tools/bin/flutter_tools.dart
文件开始;这个类很是简单:
import 'package:flutter_tools/executable.dart' as executable;
void main(List<String> args) {
executable.main(args);
}
复制代码
因此,全部的开始应该在 executeable.dart 里面;里面主要是把全部的命令都封装成一对象,而后放到一个数组里面注册,由于咱们主要是观察 flutter packages get
这个命令,因此咱们去看下 PackagesCommand
从类构造来看,他含有子命令; PackagesGetCommand
; 先无论;由于全部的 FlutterCommand 都会执行 Future<FlutterCommandResult> runCommand()
这个方法;因此咱们来看下这个的逻辑;
@override
Future<FlutterCommandResult> runCommand() async {
// .........省略不必的
await _runPubGet(target);
final FlutterProject rootProject = FlutterProject.fromPath(target);
// 下面这行代码主要是用来刷新 .android 和 .ios的目录
await rootProject.ensureReadyForPlatformSpecificTooling(checkProjects: true);
// Get/upgrade packages in example app as well
if (rootProject.hasExampleApp) {
final FlutterProject exampleProject = rootProject.example;
await _runPubGet(exampleProject.directory.path);
await exampleProject.ensureReadyForPlatformSpecificTooling(checkProjects: true);
}
// 省略不必的
}
}
复制代码
主要刷新逻辑在 ensureReadyForPlatformSpecificTooling
/// Generates project files necessary to make Gradle builds work on Android
/// and CocoaPods+Xcode work on iOS, for app and module projects only.
Future<void> ensureReadyForPlatformSpecificTooling({bool checkProjects = false}) async {
if (!directory.existsSync() || hasExampleApp) {
return;
}
refreshPluginsList(this); // 这里更新 .flutter-plugin 文件
if ((android.existsSync() && checkProjects) || !checkProjects) {
await android.ensureReadyForPlatformSpecificTooling();// 这里更新
}
if ((ios.existsSync() && checkProjects) || !checkProjects) {
await ios.ensureReadyForPlatformSpecificTooling();// 这里更新
}
await injectPlugins(this, checkProjects: checkProjects);// 把一些channel 注册到对应的平台
}
复制代码
.flutter-plugins
文件从上面的代码能够看出, 要想 flutter package get
不去刷新,从新建立模板,只要把对应 ensureReadyForPlatformSpecificTooling() 代码不执行就行了;而后修改源码,从新编译;编译的方法在 flutter 脚本中的 4 种方式里面;