預備知識
理解 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 主要有下面幾個流程:
一、插件啟動的準備工作
在前面講解自定義插件的時候說到過,要定義一個 xxx.properties 文件,里面聲明插件的入口類,而 xxx 就是 apply plugin 時候使用的 id,這里要知道 android gradle plugin 的入口類,看 com.android.application.properties 文件就可以,內容如下:
implementation-class=com.android.build.gradle.AppPlugin
復制代碼這里定義了入口是 AppPlugin,AppPlugin 繼承自 BasePlugin。
AppPlugin 里沒有做太多的操作,主要是重寫了 createTaskManager 和 createExtension,剩下的大部分工作還是在 BasePlugin 里做的。
插件準備工作中主要做的事情:
檢查插件版本
checkPluginVersion();
復制代碼檢查 module 是否重名
this.checkModulesForErrors();
復制代碼初始化插件信息
PluginInitializer.initialize(project,
this.projectOptions);
ProfilerInitializer.init(project,
this.projectOptions);
ProcessProfileWriter.getProject(project.getPath()).setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION).setAndroidPlugin(
this.getAnalyticsPluginType()).setPluginGeneration(PluginGeneration.FIRST);
復制代碼二、配置項目
配置項目這一階段主要做的事情:
檢查 gradle 版本是否匹配
this.checkGradleVersion();
復制代碼創建 AndroidBuilder和 DataBindingBuilder引入 java plugin 和 jacoco pluginthis.project.getPlugins().apply(JavaBasePlugin.
class);
this.project.getPlugins().apply(JacocoPlugin.
class);
復制代碼設置構建完成以后的混存清理工作 添加了 BuildListener,在 buildFinished 回調里做緩存清理工作三、配置 Extension
實現在 BasePlugin.configureExtension()
這一階段主要做了下面幾個事情:
創建 AppExtension,也就是 build.gradle 里用到的 android {} dslthis.extension =
this.createExtension(...);
protected BaseExtension createExtension(...) {
return (BaseExtension)project.getExtensions().create(
"android", AppExtension.
class,
new Object[]{project, projectOptions, instantiator, androidBuilder, sdkHandler, buildTypeContainer, productFlavorContainer, signingConfigContainer, buildOutputs, extraModelInfo});
}
復制代碼創建依賴管理,ndk管理,任務管理,variant管理注冊新增配置的回調函數,包括 signingConfig,buildType,productFlavor
signingConfigContainer.whenObjectAdded(
variantManager::addSigningConfig);
buildTypeContainer.whenObjectAdded(buildType -> {SigningConfig signingConfig =signingConfigContainer.findByName(BuilderConstants.DEBUG);buildType.init(signingConfig);variantManager.addBuildType(buildType);});
productFlavorContainer.whenObjectAdded(
variantManager::addProductFlavor);
public void addSigningConfig(SigningConfig signingConfig) {
this.signingConfigs.put(signingConfig.getName(), signingConfig);
}
public void addProductFlavor(CoreProductFlavor productFlavor) {String name = productFlavor.getName();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<CoreProductFlavor> productFlavorData =
new ProductFlavorData(productFlavor, mainSourceSet, androidTestSourceSet, unitTestSourceSet,
this.project);
this.productFlavors.put(productFlavor.getName(), productFlavorData);}
}
復制代碼創建默認的 debug 簽名,創建 debug 和 release 兩個 buildTypevariantFactory.createDefaultComponents(buildTypeContainer, productFlavorContainer, signingConfigContainer);
public void createDefaultComponents(...) {signingConfigs.create(
"debug");buildTypes.create(
"debug");buildTypes.create(
"release");
}
復制代碼四、創建不依賴 flavor 的 task
上述準備,配置階段完成以后,就開始創建構建需要的 Task 了,是在 BasePlugin.createTasks() 里實現的,主要有兩步,創建不依賴 flavor 的 task 和創建構建 task。
先看不依賴 flavor 的 task,其實現在 TaskManager.createTasksBeforeEvaluate()。
這里主要創建了幾個 task,包括 uninstallAll,deviceCheck,connectedCheck,preBuild,extractProguardFiles,sourceSets,assembleAndroidTest,compileLint,lint,lintChecks,cleanBuildCacheresolveConfigAttr,consumeConfigAttr。
這些 task 都是不需要依賴 flavor 數據的公共 task。
五、創建構建 task
在介紹下面的流程之前,先明確幾個概念,flavor,dimension,variant。
在 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。
其中重要的幾個方法:
List<ProductFlavorCombo<CoreProductFlavor>> flavorComboList =ProductFlavorCombo.createCombinations(flavorDimensionList,flavorDsl);
for (ProductFlavorCombo<CoreProductFlavor>
flavorCombo : flavorComboList) {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;
public AndroidTask<PackageSplitRes> packageSplitResourcesTask;
public AndroidTask<PackageSplitAbi> packageSplitAbiTask;
public RenderscriptCompile renderscriptCompileTask;
public MergeResources mergeResourcesTask;
public ManifestProcessorTask processManifest;
public MergeSourceSetFolders mergeAssetsTask;
public GenerateBuildConfig generateBuildConfigTask;
public GenerateResValues generateResValuesTask;
public Sync processJavaResourcesTask;
public NdkCompile ndkCompileTask;
public JavaCompile javacTask;
public Task compileTask;
public Task javaCompilerTask;
}
復制代碼VariantData 里保存了很多 task,下一步就要創建這些 task。
2.createTasksForVariantData
創建完 variant 數據,就要給 每個 variantData 創建對應的 task,對應的 task 有 assembleXXXTask,prebuildXXX,generateXXXSource,generateXXXResources,generateXXXAssets,processXXXManifest 等等,重點關注幾個方法:
VariantManager.createAssembleTaskForVariantData()
TaskManager.createTasksForVariantScope()
TaskManager.createPostCompilationTasks()
void createTasksForVariantScope() {
this.createCheckManifestTask(tasks, variantScope);
this.handleMicroApp(tasks, variantScope);
this.createDependencyStreams(tasks, variantScope);
this.createApplicationIdWriterTask(tasks, variantScope);
this.createMergeApkManifestsTask(tasks, variantScope);
this.createGenerateResValuesTask(tasks, variantScope);
this.createRenderscriptTask(tasks, variantScope);
this.createMergeResourcesTask(tasks, variantScope,
true);
this.createMergeAssetsTask(tasks, variantScope, (BiConsumer)
null);
this.createBuildConfigTask(tasks, variantScope);
this.createApkProcessResTask(tasks, variantScope);
this.createProcessJavaResTask(tasks, variantScope);
this.createAidlTask(tasks, variantScope);
this.createShaderTask(tasks, variantScope);
this.createNdkTasks(tasks, variantScope);
this.createExternalNativeBuildJsonGenerators(variantScope);
this.createExternalNativeBuildTasks(tasks, variantScope);
this.createMergeJniLibFoldersTasks(tasks, variantScope);
this.createDataBindingTasksIfNecessary(tasks, variantScope);
this.addCompileTask(tasks, variantScope); createStripNativeLibraryTask(tasks, variantScope);
this.createSplitTasks(tasks, variantScope);
this.createPackagingTask(tasks, variantScope, buildInfoWriterTask);
this.createLintTasks(tasks, variantScope);
}
void createPostCompilationTasks() {
for (
int i =
0, count = customTransforms.size(); i < count; i++) {Transform transform = customTransforms.get(i);transformManager.addTransform(tasks, variantScope, transform).ifPresent(t -> {
if (!deps.isEmpty()) {t.dependsOn(tasks, deps);}
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【Android 修煉手冊】系列內容 每周五更新
歡迎關注下面賬號,獲取更新:
微信搜索公眾號: ZYLAB
Github
掘金
總結
以上是生活随笔為你收集整理的【Android 修炼手册】Gradle 篇 -- Android Gradle Plugin 主要流程分析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。