解決 flutter module 中 .android 和 .ios 目錄不被覆蓋的問題

在對 flutter module 進行修改的時候,不知道爲何,會發現 .android 目錄下和 .ios 目錄下的文件會被修改覆蓋掉;後來發現,只要咱們變更 pubspec.yaml 的文件, 而後執行命令 flutter packages get,就會從新從flutter 模板中替換 .android.ios 目錄; 由於咱們的 .android目錄下有本身定義 gradle 腳本(主要爲了解決打包aar的問題);就不但願這個 gradle 被覆蓋;android

解決方法

  1. 在 flutter-sdk 中修改模板,把本身寫好的 gradle 放到模板中;
  2. 找到執行 flutter packages get 背後的邏輯,經過修改邏輯代碼,不去覆蓋現有的代碼;

替換模板的目錄

全部的模板目錄都在Flutter_HOME/packages/flutter_tools/templates 下面:ios

以上紅色箭頭的地方,是我替換和添加的模板代碼;ios 應該也能夠找到相應的模板進行添加和修改;git

查看 flutter 的 shell 腳本命令

1. flutter 命令的開始

由於是 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

2. flutter_tools.snapshot 文件的生成

能夠繼續查看一下 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 源碼;編輯器

3. 稍微看下須要編譯 flutter_tools.snapshot 的條件是什麼

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;

  • flutter_tools.snapshot 文件不存在
  • STAMP_PATH 這個文件的 size 爲0, 主要用來緩存一個 git commit
  • 若是被緩存的 git commit 和 revision 不相同也會觸發,revision = git rev-parse HEAD
  • 若是 pubspec.yaml 文件最後修改時間大於pubspec.lock 文件 (nt: new then)

通過以上3 點,接下來,咱們能夠去看下 flutter_tools 的源碼了;

查看 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 註冊到對應的平臺
  }
複製代碼
  • refreshPluginsList(this): 刷新 .flutter-plugins 文件
  • android.ensureReadyForPlatformSpecificTooling(): 刷新 .android 文件
  • await ios.ensureReadyForPlatformSpecificTooling(): 刷新 .ios 文件
  • injectPlugins(this, checkProjects: checkProjects): 把一些channel 註冊到對應的平臺, GeneratedPluginRegistrant 裏面相關的代碼生成;

從上面的代碼能夠看出, 要想 flutter package get 不去刷新,從新建立模板,只要把對應 ensureReadyForPlatformSpecificTooling() 代碼不執行就行了;而後修改源碼,從新編譯;編譯的方法在 flutter 腳本中的 4 種方式裏面;

相關文章
相關標籤/搜索