在對 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 種方式裏面;