解决 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 种方式里面;

相关文章
相关标签/搜索