项目构建流程
下面分析一下aspectd是的执行过程是怎样的,我们先看一下aspectd给flutter tools打的git patch上的代码。
主要改了两个类。
一个新添加的aspectd.dart,另一个common.dart是系统原有的类。
我们先看common.dart
可以看到对KernelSnapShot类的build方法做了一些修改。
也就是修改了原来生成dill的流程。
把原来的编译流程抽取出来到buildImpl()方法中。增加了如下判断。
await buildImpl(environment);
if (await AspectdHook.isAspectdEnabled()) {
await AspectdHook().runBuildDillCommand(environment);
}
这里就是上面所说的,如果不是aspectd的项目,就走普通的构建流程。
static Future<bool> isAspectdEnabled() async {
final Directory currentDirectory = globals.fs.currentDirectory;
final Directory aspectdDirectory =
getAspectdImplDirectory(currentDirectory);
if (!aspectdDirectory.existsSync()) {
return false;
}
final String aspectdImplPackagesPath = globals.fs.path
.join(aspectdDirectory.absolute.path, globalPackagesPath);
final Directory flutterFrontendServerDirectory =
await getFlutterFrontendServerDirectory(aspectdImplPackagesPath);
if (!(aspectdDirectory.existsSync() &&
flutterFrontendServerDirectory.existsSync() &&
currentDirectory.absolute.path != aspectdDirectory.absolute.path &&
globals.fs
.file(globals.fs.path.join(aspectdDirectory.path, 'pubspec.yaml'))
.existsSync() &&
globals.fs
.file(
globals.fs.path.join(aspectdDirectory.path, globalPackagesPath))
.existsSync() &&
globals.fs
.file(globals.fs.path.join(
aspectdDirectory.path, 'lib', aspectdImplPackageName + '.dart'))
.existsSync())) {
return false;
}
return await checkAspectdFlutterFrontendServerSnapshot(
aspectdImplPackagesPath);
}
可以看到这里只要有一个条件不满足就会return false:
1.aspectdDirectory是否存在
2.flutterFrontendServerDirectory是否存在
3.当前目录是否包含pubspec,aspectd_impl.dart
等等
然后check aspectd hook过的FrontendServerSnapshot文件是否存在。
如果不存在,则去调用命令行process去生成一个snapshot对象。
static Future<bool> checkAspectdFlutterFrontendServerSnapshot(
String packagesPath) async {
final Directory flutterFrontendServerDirectory =
await getFlutterFrontendServerDirectory(packagesPath);
final String aspectdFlutterFrontendServerSnapshot = globals.fs.path.join(
flutterFrontendServerDirectory.absolute.path,
frontendServerDartSnapshot);
final String defaultFlutterFrontendServerSnapshot = globals.artifacts
.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk);
if (!globals.fs.file(aspectdFlutterFrontendServerSnapshot).existsSync()) {
final String dartSdkDir = await getDartSdkDependency(
(await getPackagePathFromConfig(packagesPath, 'aspectd'))
.absolute
.path);
final String frontendServerPackageConfigJsonFile =
'${flutterFrontendServerDirectory.absolute.path}/package_config.json';
final String rebasedFrontendServerPackageConfigJsonFile =
'${flutterFrontendServerDirectory.absolute.path}/rebased_package_config.json';
String frontendServerPackageConfigJson = globals.fs
.file(frontendServerPackageConfigJsonFile)
.readAsStringSync();
frontendServerPackageConfigJson = frontendServerPackageConfigJson
.replaceAll('../../../third_party/dart/', dartSdkDir);
globals.fs
.file(rebasedFrontendServerPackageConfigJsonFile)
.writeAsStringSync(frontendServerPackageConfigJson);
final List<String> commands = <String>[
globals.artifacts.getArtifactPath(Artifact.engineDartBinary),
'--deterministic',
'--packages=$rebasedFrontendServerPackageConfigJsonFile',
'--snapshot=$aspectdFlutterFrontendServerSnapshot',
'--snapshot-kind=kernel',
'${flutterFrontendServerDirectory.absolute.path}/starter.dart'
];
final ProcessResult processResult =
await globals.processManager.run(commands);
globals.fs.file(rebasedFrontendServerPackageConfigJsonFile).deleteSync();
if (processResult.exitCode != 0 ||
globals.fs.file(aspectdFlutterFrontendServerSnapshot).existsSync() ==
false) {
throwToolExit(
'Aspectd unexpected error: ${processResult.stderr.toString()}');
}
}
if (globals.fs.file(defaultFlutterFrontendServerSnapshot).existsSync()) {
globals.fs.file(defaultFlutterFrontendServerSnapshot).deleteSync();
}
globals.fs
.file(aspectdFlutterFrontendServerSnapshot)
.copySync(defaultFlutterFrontendServerSnapshot);
return true;
}
最后删除sdk默认目录下的frontendServerSnapshot
回到common.dart中,如果AspectdHook.isAspectdEnabled()是true,
就去走runBuildDillCommand();
Future<void> runBuildDillCommand(Environment environment) async {
final Directory aspectdDir =
getAspectdImplDirectory(globals.fs.currentDirectory);
final Directory previousDirectory = globals.fs.currentDirectory;
globals.fs.currentDirectory = aspectdDir;
String relativeDir = environment.outputDir.absolute.path
.substring(environment.projectDir.absolute.path.length + 1);
final String outputDir = globals.fs.path.join(aspectdDir.path, relativeDir);
final String buildDir =
globals.fs.path.join(aspectdDir.path, '.dart_tool', 'flutter_build');
final Map<String, String> defines = environment.defines;
defines[kTargetFile] = globals.fs.path
.join(aspectdDir.path, 'lib', aspectdImplPackageName + '.dart');
final Environment auxEnvironment = Environment(
projectDir: aspectdDir,
outputDir: globals.fs.directory(outputDir),
cacheDir: environment.cacheDir,
flutterRootDir: environment.flutterRootDir,
fileSystem: environment.fileSystem,
logger: environment.logger,
artifacts: environment.artifacts,
processManager: environment.processManager,
engineVersion: environment.engineVersion,
buildDir: globals.fs.directory(buildDir),
defines: defines,
inputs: environment.inputs);
const KernelSnapshot auxKernelSnapshot = KernelSnapshot();
final CompilerOutput compilerOutput =
await auxKernelSnapshot.buildImpl(auxEnvironment);
final String aspectdDill = compilerOutput.outputFilename;
final File originalDillFile = globals.fs.file(
globals.fs.path.join(environment.buildDir.absolute.path, 'app.dill'));
if (originalDillFile.existsSync()) {
originalDillFile.renameSync(originalDillFile.absolute.path + '.bak');
}
globals.fs.file(aspectdDill).copySync(originalDillFile.absolute.path);
globals.fs.currentDirectory = previousDirectory;
}
1.把路径切换到aspectd_impl所在的目录,并保存之前的目录
2.在aspectd_impl的.dart_tool/flutter_build目录下生成
然后把生成的app.dill从aspectd_impl目录拷贝到example工程目录。如果原来生成的app.dill已经存在,会先把原来的app.dill重命名为app.dill.bak
最后再切换回最开始的目录。
所以最后参与打包生成的app.dill是由aspectd_impl下构建好拷贝过来的。