|
|
|
@ -2,17 +2,17 @@ |
|
|
|
|
Android Gradle Plugin 主要流程分析 |
|
|
|
|
--- |
|
|
|
|
|
|
|
|
|
#### 前言 |
|
|
|
|
### 前言 |
|
|
|
|
|
|
|
|
|
> 本文摘自:[Android Gradle Plugin 插件主要流程](https://github.com/5A59/android-training/blob/master/gradle/android_gradle_plugin-%E4%B8%BB%E8%A6%81%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90.md) |
|
|
|
|
> |
|
|
|
|
> 感谢美团大佬 [@5A59](https://github.com/5A59) 的分享! |
|
|
|
|
|
|
|
|
|
#### 概述 |
|
|
|
|
### 概述 |
|
|
|
|
|
|
|
|
|
![Android Plugin 流程分析概述.png](https://i.loli.net/2019/08/14/Ubpnexm3cK5yOPW.png) |
|
|
|
|
|
|
|
|
|
#### 准备工作 |
|
|
|
|
### 准备工作 |
|
|
|
|
|
|
|
|
|
这个阶段主要有过程: |
|
|
|
|
|
|
|
|
@ -47,7 +47,7 @@ AppPlugin 里面没有做过多的操作,主要是重写了 createTaskManager |
|
|
|
|
.setPluginGeneration(GradleBuildProject.PluginGeneration.FIRST); |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
#### 配置项目 |
|
|
|
|
### 配置项目 |
|
|
|
|
|
|
|
|
|
这个阶段有四个过程: |
|
|
|
|
|
|
|
|
@ -72,7 +72,7 @@ private void configureProject(){ |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
#### 配置 Extension |
|
|
|
|
### 配置 Extension |
|
|
|
|
|
|
|
|
|
这一阶段主要做了以下几件事情: |
|
|
|
|
|
|
|
|
@ -137,7 +137,7 @@ private void configureProject(){ |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
#### 创建不依赖 flavor 的 Task |
|
|
|
|
### 创建不依赖 flavor 的 Task |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
private void createTasks() { |
|
|
|
@ -169,7 +169,7 @@ private void configureProject(){ |
|
|
|
|
|
|
|
|
|
这些 task 都是不需要依赖 flavor 数据的公共 task。 |
|
|
|
|
|
|
|
|
|
#### 创建构建 Task |
|
|
|
|
### 创建构建 Task |
|
|
|
|
|
|
|
|
|
在介绍下面的流程之前,先明确几个概念,flavor、dimension、variant。 |
|
|
|
|
|
|
|
|
@ -201,3 +201,129 @@ createAndroidTasks 的调用时机和上面不一样,是在 project.afterEvalu |
|
|
|
|
|
|
|
|
|
在 BasePlugin.createAndroidTasks 里,是调用 VariantManager.createAndroidTasks 完成工作的。 |
|
|
|
|
|
|
|
|
|
创建 task 的时候,会先通过 populateVariantDataList 生成 flavor 相关的数据结构,然后调用 createTasksForVariantData 创建 flavor 对应的 task。 |
|
|
|
|
|
|
|
|
|
分别看下这两个方法所做的事情: |
|
|
|
|
|
|
|
|
|
1. populateVariantDataList |
|
|
|
|
|
|
|
|
|
在方法里,会先根据 flavor 和 dimension 创建对应的组合,存放在 flavorComboList 里,之后调用 createVariantDataForProductFlavors 创建对应的 VariantData。 |
|
|
|
|
|
|
|
|
|
其中重要的几个方法: |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
// 创建 flavor 和 dimension 的组合 |
|
|
|
|
List<ProductFlavorCombo<CoreProductFlavor>> flavorComboList = |
|
|
|
|
ProductFlavorCombo.createCombinations( |
|
|
|
|
flavorDimensionList, |
|
|
|
|
flavorDsl); |
|
|
|
|
// 为每个组合创建 VariantData |
|
|
|
|
for (ProductFlavorCombo<CoreProductFlavor> flavorCombo : flavorComboList) { |
|
|
|
|
//noinspection unchecked |
|
|
|
|
createVariantDataForProductFlavors( |
|
|
|
|
(List<ProductFlavor>) (List) flavorCombo.getFlavorList()); |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
创建出来的 VariantData 都是 BaseVariantData 的子类,里面保存了一些 Task,可以看一下 BaseVariantData 里的一些重要的结构,对 BaseVariantData 有个大概的了解。 |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
public abstract class BaseVariantData implements TaskContainer { |
|
|
|
|
private final GradleVariantConfiguration variantConfiguration; |
|
|
|
|
private VariantDependencies variantDependency; |
|
|
|
|
private final VariantScope scope; |
|
|
|
|
public Task preBuildTask; |
|
|
|
|
public Task sourceGenTask; |
|
|
|
|
public Task resourceGenTask; // 资源处理 |
|
|
|
|
public Task assetGenTask; |
|
|
|
|
public CheckManifest checkManifestTask; // 检测manifest |
|
|
|
|
public AndroidTask<PackageSplitRes> packageSplitResourcesTask; // 打包资源 |
|
|
|
|
public AndroidTask<PackageSplitAbi> packageSplitAbiTask; |
|
|
|
|
public RenderscriptCompile renderscriptCompileTask; |
|
|
|
|
public MergeResources mergeResourcesTask; // 合并资源 |
|
|
|
|
public ManifestProcessorTask processManifest; // 处理 manifest |
|
|
|
|
public MergeSourceSetFolders mergeAssetsTask; // 合并 assets |
|
|
|
|
public GenerateBuildConfig generateBuildConfigTask; // 生成 BuildConfig |
|
|
|
|
public GenerateResValues generateResValuesTask; |
|
|
|
|
public Sync processJavaResourcesTask; |
|
|
|
|
public NdkCompile ndkCompileTask; // ndk 编译 |
|
|
|
|
public JavaCompile javacTask; |
|
|
|
|
public Task compileTask; |
|
|
|
|
public Task javaCompilerTask; // java 文件编译 |
|
|
|
|
// ... |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
VariantData 里保存了很多 Task,下一步就是要创建这些 task。 |
|
|
|
|
|
|
|
|
|
2. createTasksForVariantData |
|
|
|
|
|
|
|
|
|
创建完 variant 数据,就要给每个 variantData 创建对应的 task,对应的 task 有 assembleXxxTask、prebuildXxx、generateXxxSource、generateXxxResources、generateXxxAssets、processXxxManifest 等等,重点关注几个方法: |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
VariantManager.createAssembleTaskForVariantData() // 创建 assembleXXXTask |
|
|
|
|
TaskManager.createTasksForVariantScope() // 是一个抽象类,具体实现在 ApplicationTaskManager.createTasksForVariantScope() |
|
|
|
|
TaskManager.createPostCompilationTasks() // 创建 .class to dex 的 task, 创建 transformTask,我们创建的 transform 就是这个阶段添加进来的,是在 addCompileTask 里调用的 |
|
|
|
|
|
|
|
|
|
// createTasksForVariantScope 是一个抽象方法,具体实现在子类中,可以看一下 ApplicationTaskManager.createTasksForVariantScope() |
|
|
|
|
// createTasksForVariantScope 里的实现,如果在业务中有需要查看相关 task 源码时,可以来这里找 |
|
|
|
|
void createTasksForVariantScope() { |
|
|
|
|
this.createCheckManifestTask(tasks, variantScope); // 检测 manifest |
|
|
|
|
this.handleMicroApp(tasks, variantScope); |
|
|
|
|
this.createDependencyStreams(tasks, variantScope); |
|
|
|
|
this.createApplicationIdWriterTask(tasks, variantScope); // application id |
|
|
|
|
this.createMergeApkManifestsTask(tasks, variantScope); // 合并 manifest |
|
|
|
|
this.createGenerateResValuesTask(tasks, variantScope); |
|
|
|
|
this.createRenderscriptTask(tasks, variantScope); |
|
|
|
|
this.createMergeResourcesTask(tasks, variantScope, true); // 合并资源文件 |
|
|
|
|
this.createMergeAssetsTask(tasks, variantScope, (BiConsumer)null); // 合并 assets |
|
|
|
|
this.createBuildConfigTask(tasks, variantScope); // 生成 BuildConfig |
|
|
|
|
this.createApkProcessResTask(tasks, variantScope); // 处理资源 |
|
|
|
|
this.createProcessJavaResTask(tasks, variantScope); |
|
|
|
|
this.createAidlTask(tasks, variantScope); // 处理 aidl |
|
|
|
|
this.createShaderTask(tasks, variantScope); |
|
|
|
|
this.createNdkTasks(tasks, variantScope); // 处理 ndk |
|
|
|
|
this.createExternalNativeBuildJsonGenerators(variantScope); |
|
|
|
|
this.createExternalNativeBuildTasks(tasks, variantScope); |
|
|
|
|
this.createMergeJniLibFoldersTasks(tasks, variantScope); // 合并 jni |
|
|
|
|
this.createDataBindingTasksIfNecessary(tasks, variantScope); // 处理 databinding |
|
|
|
|
this.addCompileTask(tasks, variantScope); |
|
|
|
|
createStripNativeLibraryTask(tasks, variantScope); |
|
|
|
|
this.createSplitTasks(tasks, variantScope); |
|
|
|
|
this.createPackagingTask(tasks, variantScope, buildInfoWriterTask); // 打包 apk |
|
|
|
|
this.createLintTasks(tasks, variantScope); // lint |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// createPostCompilationTasks 实现: |
|
|
|
|
// 处理 Android Transform |
|
|
|
|
void createPostCompilationTasks() { |
|
|
|
|
for (int i = 0, count = customTransforms.size(); i < count; i++) { |
|
|
|
|
Transform transform = customTransforms.get(i); |
|
|
|
|
// TransformManager.addTransform 实际上是为 transform 创建了一个 Task |
|
|
|
|
transformManager |
|
|
|
|
.addTransform(tasks, variantScope, transform) |
|
|
|
|
.ifPresent(t -> { |
|
|
|
|
if (!deps.isEmpty()) { |
|
|
|
|
t.dependsOn(tasks, deps); |
|
|
|
|
} |
|
|
|
|
// if the task is a no-op then we make assemble task depend on it. |
|
|
|
|
if (transform.getScopes().isEmpty()) { |
|
|
|
|
variantScope.getAssembleTask().dependsOn(tasks, t); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### 总结 |
|
|
|
|
|
|
|
|
|
![plugin-summary.png](https://i.loli.net/2019/08/22/1zcRLBIFxNrQqDg.png) |
|
|
|
|
|
|
|
|
|
这里总结几个要点: |
|
|
|
|
|
|
|
|
|
1. com.android.application 入口类是 AppPlugin,但大部分工作都是在 BasePlugin 里完成的。 |
|
|
|
|
2. build.gradle 里见到的 android {} dsl 是在 BasePlugin.configureExtension() 里声明的。 |
|
|
|
|
3. 主要的 task 是在 BasePlugin.createAndroidTask 里生成的。 |
|
|
|
|
4. 主要 Task 的实现可以在 TaskManager 中找到。 |
|
|
|
|
5. Transform 会转化为 TransformTask。 |
|
|
|
|
|
|
|
|
|