【Android 修煉手冊】Gradle 篇 -- Android Gradle Plugin 主要流程分析
預備知識
- 理解 gradle 的基本開發
- 了解 gradle task 和 plugin 使用及開發
- 了解 android gradle plugin 的使用
看完本文可以達到什么程度
- 了解 android gradle plugin 的構建流程
- 了解 android gradle plugin 的主要 task 的實現
- 學會 hook android 構建流程,添加自己想要的功能
閱讀前准備工作
- 項目添加 android gradle plugin 依賴
compile 'com.android.tools.build:gradle:3.0.1'
通過這種方式,可以直接依賴 plugin 的源碼,讀起來比較方便。
2. 官方對照源碼地址 android gradle plugin 源碼地址
大家可以直接 clone EasyGradle 項目,把 android-gradle-plugin-source/build.gradle 里的 implementation 'com.android.tools.build:gradle:3.0.1' 注釋打開就可以了。
com.android.application 主要有下面幾個流程:

一、插件啟動的准備工作

implementation-class=com.android.build.gradle.AppPlugin
這里定義了入口是 AppPlugin,AppPlugin 繼承自 BasePlugin。
AppPlugin 里沒有做太多的操作,主要是重寫了 createTaskManager 和 createExtension,剩下的大部分工作還是在 BasePlugin 里做的。
插件准備工作中主要做的事情:
1.檢查插件版本
// method: BasePlugin.apply() checkPluginVersion();
2.檢查 module 是否重名
// method: BasePlugin.apply() // 方法中會遍歷所有子項目,判斷是否有重復的 id this.checkModulesForErrors();
3.初始化插件信息
// method: BasePlugin.apply() PluginInitializer.initialize(project, this.projectOptions); // 創建 Profiler 文件 ProfilerInitializer.init(project, this.projectOptions); // profiler 信息中寫入 plugin 版本 ProcessProfileWriter.getProject(project.getPath()).setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION).setAndroidPlugin(this.getAnalyticsPluginType()).setPluginGeneration(PluginGeneration.FIRST);
二、配置項目

配置項目這一階段主要做的事情:
1.檢查 gradle 版本是否匹配
// method: BasePlugin.configureProject() this.checkGradleVersion();
2.創建 AndroidBuilder和 DataBindingBuilder
3.引入 java plugin 和 jacoco plugin
this.project.getPlugins().apply(JavaBasePlugin.class); this.project.getPlugins().apply(JacocoPlugin.class);
4.設置構建完成以后的混存清理工作 添加了 BuildListener,在 buildFinished 回調里做緩存清理工作
三、配置 Extension
實現在 BasePlugin.configureExtension()
這一階段主要做了下面幾個事情:
1.創建 AppExtension,也就是 build.gradle 里用到的 android {} dsl
this.extension = this.createExtension(...); // AppPlugin 中實現了 createExtension,創建了 android {} dsl protected BaseExtension createExtension(...) { return (BaseExtension)project.getExtensions().create("android", AppExtension.class, new Object[]{project, projectOptions, instantiator, androidBuilder, sdkHandler, buildTypeContainer, productFlavorContainer, signingConfigContainer, buildOutputs, extraModelInfo}); }
2.創建依賴管理,ndk管理,任務管理,variant管理
3.注冊新增配置的回調函數,包括 signingConfig,buildType,productFlavor
// BasePlugin.java createExtension() // map the whenObjectAdded callbacks on the containers. signingConfigContainer.whenObjectAdded(variantManager::addSigningConfig); buildTypeContainer.whenObjectAdded( buildType -> { SigningConfig signingConfig = signingConfigContainer.findByName(BuilderConstants.DEBUG); buildType.init(signingConfig); // addBuildType,會檢查命名是否合法,然后創建 BuildTypeData variantManager.addBuildType(buildType); }); // addProductFlavor 會檢查命名是否合法,然后創建 ProductFlavorData productFlavorContainer.whenObjectAdded(variantManager::addProductFlavor); // VariantManager.java // addSigningConfig 就是在 signingConfigs 里新增一個配置 public void addSigningConfig(SigningConfig signingConfig) { this.signingConfigs.put(signingConfig.getName(), signingConfig); } // VariantManager.java public void addProductFlavor(CoreProductFlavor productFlavor) { String name = productFlavor.getName(); // checkName 會檢查 checkName(name, "ProductFlavor"); if(this.buildTypes.containsKey(name)) { throw new RuntimeException("ProductFlavor names cannot collide with BuildType names"); } else { // 獲取源碼位置 DefaultAndroidSourceSet mainSourceSet = (DefaultAndroidSourceSet)this.extension.getSourceSets().maybeCreate(productFlavor.getName()); DefaultAndroidSourceSet androidTestSourceSet = null; DefaultAndroidSourceSet unitTestSourceSet = null; if(this.variantFactory.hasTestScope()) { // 獲取單測源碼位置 androidTestSourceSet = (DefaultAndroidSourceSet)this.extension.getSourceSets().maybeCreate(computeSourceSetName(productFlavor.getName(), VariantType.ANDROID_TEST)); unitTestSourceSet = (DefaultAndroidSourceSet)this.extension.getSourceSets().maybeCreate(computeSourceSetName(productFlavor.getName(), VariantType.UNIT_TEST)); } // 創建 productFlavorData 對象 ProductFlavorData<CoreProductFlavor> productFlavorData = new ProductFlavorData(productFlavor, mainSourceSet, androidTestSourceSet, unitTestSourceSet, this.project); this.productFlavors.put(productFlavor.getName(), productFlavorData); } }
4.創建默認的 debug 簽名,創建 debug 和 release 兩個 buildType
variantFactory.createDefaultComponents( buildTypeContainer, productFlavorContainer, signingConfigContainer); // ApplicationVariantFactory.java public void createDefaultComponents(...) { signingConfigs.create("debug"); buildTypes.create("debug"); buildTypes.create("release"); }
四、創建不依賴 flavor 的 task
先看不依賴 flavor 的 task,其實現在 TaskManager.createTasksBeforeEvaluate()。
這里主要創建了幾個 task,包括 uninstallAll,deviceCheck,connectedCheck,preBuild,extractProguardFiles,sourceSets,assembleAndroidTest,compileLint,lint,lintChecks,cleanBuildCacheresolveConfigAttr,consumeConfigAttr。
這些 task 都是不需要依賴 flavor 數據的公共 task。
五、創建構建 task
在 android gradle plugin 3.x 之后,每個 flavor 必須對應一個 dimension,可以理解為 flavor 的分組,然后不同 dimension 里的 flavor 組合成一個 variant。
舉個例子:
flavorDimensions "size", "color" productFlavors { big { dimension "size" } small { dimension "size" } blue { dimension "color" } red { dimension "color" } }
上面配置對應生成的 variant 就是 bigBlue,bigRed,smallBlue,smallRed,在這個基礎上,再加上 buildTypes,就是 bigBlueDebug,bigRedDebug,smallBlueDebug,smallRedDebug,bigBlueRelease,bigRedRelease,smallBlueRelease,smallRedRelease。
createAndroidTasks 的調用時機和上面不一樣,是在 project.afterEvaluate 里調用的,還記得之前文章里說道的 afterEvaluate 回調么?這個時候所有模塊配置已經完成了。所以在這個階段可以獲取到對應的 flavor 以及其他配置了。
在 BasePlugin.createAndroidTasks 里,是調用 VariantManager.createAndroidTasks 完成工作的。
創建 task 的時候,會先通過 populateVariantDataList 生成 flavor 相關的數據結構,然后調用 createTasksForVariantData 創建 flavor 對應的 task。
分別看下這兩個方法做的事情
1.populateVariantDataList
在方法里,會先根據 flavor 和 dimension 創建對應的組合,存放在 flavorComboList 里,之后調用 createVariantDataForProductFlavors 創建對應的 VariantData。
其中重要的幾個方法:
// 創建 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 有個大概的了解。
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 等等,重點關注幾個方法:
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); } }); } }
六、總結
android gradle plugin 的主要流程基本上就結束了,主要流程圖如下所示
這里總結幾個要點:
- com.android.application 入口類是 AppPlugin,但大部分工作都是在 BasePlugin 里完成的
- build.gradle 里見到的 android {} dsl 是在 BasePlugin.configureExtension() 里聲明的
- 主要的 task 是在 BasePlugin.createAndroidTasks() 里生成的
- 主要 task 的實現可以在 TaskManager 中找到
- transform 會轉化成 TransformTask