一、源码依赖
本文基于:
android gradle plugin版本:
com.android.tools.build:gradle:2.3.0
gradle 版本:4.1
Gradle源码总共30个G,为简单起见,方便大家看源码,此处通过gradle依赖的形式来查看源码,依赖源码姿势:
创建一个新工程,app 项目目录中删除所有文件,仅留下gradle文件,依赖
apply plugin: 'java'
sourceCompatibility = 1.8
dependencies {
compile gradleApi()
compile 'com.android.tools.build:gradle:2.3.0'
}
将跟目录下的gradle文件,删除掉gradle依赖
buildscript {
repositories {
google()
jcenter()
}
dependencies {
// compile 'com.android.tools.build:gradle:2.3.0'
}
}
然后rebuild一下,就可以在External Libraries中查看到android gradle的源码已经依赖了
二、Android Gradle Plugin简介
我们知道Android gradle plugin是用来构建Android工程的gradle插件,在Android gradle 插件中,可以看到app工程和library工程所依赖的plugin是不一样的
// app 工程
apply plugin: 'com.android.application'
// library 工程
apply plugin: 'com.android.library'
而对应填写andorid块中所填写的配置也不同,这就是区分Application和Library的插件的extension块
分别为:
app工程 -> AppPlugin -> AppExtension
librar工程 -> LibraryPlugin -> LibraryExtension
对应的是AppPlugin和AppExtension,这两个插件构建的流程大抵是相同的,只是各自插件生成的任务不同,接下来我们着重分析Application插件是如何构建我们的Android应用的
三、AppPlugin的构建流程
我们先看下app工程中gradle的文件格式
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.zengshaoyi.gradledemo"
minSdkVersion 15
targetSdkVersion 25
versionCode project.ext.versionCode
versionName project.ext.versionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
跟踪apply方法,其实是进入到
AppPlugin的apply的方法,我们可以看到内部实现是直接调用父类BasePlugin的apply方法
protected void apply(@NonNull Project project) {
checkPluginVersion();
this.project = project;
ExecutionConfigurationUtil.setThreadPoolSize(project);
checkPathForErrors();
checkModulesForErrors();
ProfilerInitializer.init(project);
threadRecorder = ThreadRecorder.get();
ProcessProfileWriter.getProject(project.getPath())
.setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION)
.setAndroidPlugin(getAnalyticsPluginType())
.setPluginGeneration(GradleBuildProject.PluginGeneration.FIRST);
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,
project.getPath(),
null,
this::configureProject);
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,
project.getPath(),
null,
this::configureExtension);
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,
project.getPath(),
null,
this::createTasks);
// Apply additional plugins
for (String plugin : AndroidGradleOptions.getAdditionalPlugins(project)) {
project.apply(ImmutableMap.of("plugin", plugin));
}
}
threadRecoirder.recode()是记录最后一个参数的路径和执行的时间点,前面做了一些必要性的信息检测之前,其实主要做了以下几件事情:
// 配置项目,设置构建回调
this::configureProject
// 配置Extension
this::configureExtension
// 创建任务
this::createTasks
::是java 8引入的特性,详情可以查看java8特性 ,这里就是方法的调用
configureProject
直接来看源码
private void configureProject() {
extraModelInfo = new ExtraModelInfo(project);
checkGradleVersion();
AndroidGradleOptions.validate(project);
// Android SDK处理类
sdkHandler = new SdkHandler(project, getLogger());
// 设置项目评估阶段回调
project.afterEvaluate(p -> {
// TODO: Read flag from extension.
if (!p.getGradle().getStartParameter().isOffline()
&& AndroidGradleOptions.getUseSdkDownload(p)) {
// 相关配置依赖的下载处理
SdkLibData sdkLibData =
SdkLibData.download(getDownloader(), getSettingsController());
dependencyManager.setSdkLibData(sdkLibData);
sdkHandler.setSdkLibData(sdkLibData);
}
});
// 创建AndroidBuilder
androidBuilder = new AndroidBuilder(
project == project.getRootProject() ? project.getName() : project.getPath(),
creator,
new GradleProcessExecutor(project),
new GradleJavaProcessExecutor(project),
extraModelInfo,
getLogger(),
isVerbose());
// dataBinding的相关处理
dataBindingBuilder = new DataBindingBuilder();
dataBindingBuilder.setPrintMachineReadableOutput(
extraModelInfo.getErrorFormatMode() ==
ExtraModelInfo.ErrorFormatMode.MACHINE_PARSABLE);
// Apply the Java and Jacoco plugins.
project.getPlugins().apply(JavaBasePlugin.class);
project.getPlugins().apply(JacocoPlugin.class);
// 给assemble任务添加描述
project.getTasks()
.getByName("assemble")
.setDescription(
"Assembles all variants of all applications and secondary packages.");
...
可以看到 configureProject 方法中在 project.afterEvaluate 设置了回调,当项目评估结束时,根据项目配置情况,设置 dependece 依赖;创建了 AndroidBuilder 对象,这个对象是用来合并manifest 和创建 dex 等作用,后面在创建任务的过程中会使用到,结下来继续看 configureProject 的源码
// call back on execution. This is called after the whole build is done (not
// after the current project is done).
// This is will be called for each (android) projects though, so this should support
// being called 2+ times.
// 设置构建回调
project.getGradle()
.addBuildListener(
new BuildListener() {
private final LibraryCache libraryCache = LibraryCache.getCache();
@Override
public void buildStarted(Gradle gradle) {}
@Override
public void settingsEvaluated(Settings settings) {}
@Override
public void projectsLoaded(Gradle gradle) {}
@Override
public void projectsEvaluated(Gradle gradle) {}
@Override
public void buildFinished(BuildResult buildResult) {
ExecutorSingleton.shutdown();
sdkHandler.unload();
threadRecorder.record(
ExecutionType.BASE_PLUGIN_BUILD_FINISHED,
project.getPath(),
null,
() -> {
// 当任务执行完成时,清楚dex缓存
PreDexCache.getCache()
.clear(
FileUtils.join(
project.getRootProject()
.getBuildDir(),
FD_INTERMEDIATES,
"dex-cache",
"cache.xml"),
getLogger());
JackConversionCache.getCache()
.clear(
FileUtils.join(
project.getRootProject()
.getBuildDir(),
FD_INTERMEDIATES,
"jack-cache",
"cache.xml"),
getLogger());
libraryCache.unload();
Main.clearInternTables();
});
}
});
// 设置创建有向图任务回调
project.getGradle()
.getTaskGraph()
.addTaskExecutionGraphListener(
taskGraph -> {
for (Task task : taskGraph.getAllTasks()) {
// TransformTask是class编译成dex的重要任务
if (task instanceof TransformTask) {
Transform transform = ((TransformTask) task).getTransform();
if (transform instanceof DexTransform) {
PreDexCache.getCache()
.load(
FileUtils.join(
project.getRootProject()
.getBuildDir(),
FD_INTERMEDIATES,
"dex-cache",
"cache.xml"));
break;
} else if (transform instanceof JackPreDexTransform) {
JackConversionCache.getCache()
.load(
FileUtils.join(
project.getRootProject()
.getBuildDir(),
FD_INTERMEDIATES,
"jack-cache",
"cache.xml"));
break;
}
}
}
});
这里在添加了 BuildListener,在 buildFinished 的时候清楚了dex缓存,而在任务有向图创建的回调中,判断是否是 DexTransfrom,从而从缓存中加载dex。
总结一下 configureProject 做的事情,主要是进行版本有效性的判断,创建了 AndroidBuilder 对象,并设置了构建流程的回调来处理依赖和dex的加载和缓存清理。
configureExtension
这个阶段就是配置 extension 的阶段,就是创建我们 android 块中的可配置的对象
private void configureExtension() {
final NamedDomainObjectContainer<BuildType> buildTypeContainer =
project.container(
BuildType.class,
new BuildTypeFactory(instantiator, project, project.getLogger()));
final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer =
project.container(
ProductFlavor.class,
new ProductFlavorFactory(
instantiator, project, project.getLogger(), extraModelInfo));
final NamedDomainObjectContainer<SigningConfig> signingConfigContainer =
project.container(SigningConfig.class, new SigningConfigFactory(instantiator));
extension =
createExtension(
project,
instantiator,
androidBuilder,
sdkHandler,
buildTypeContainer,
productFlavorContainer,
signingConfigContainer,
extraModelInfo);
...
首先创建了 BuildType、ProductFlavor、SigningConfig 三个类型的Container,接着传入到了createExtension方法中,点入查看是个抽象的方法,各自的实现在子类中,这里也就是我们的AppPlugin 中
@NonNull
@Override
protected BaseExtension createExtension(
@NonNull Project project,
@NonNull Instantiator instantiator,
@NonNull AndroidBuilder androidBuilder,
@NonNull SdkHandler sdkHandler,
@NonNull NamedDomainObjectContainer<BuildType> buildTypeContainer,
@NonNull NamedDomainObjectContainer<ProductFlavor> productFlavorContainer,
@NonNull NamedDomainObjectContainer<SigningConfig> signingConfigContainer,
@NonNull ExtraModelInfo extraModelInfo) {
return project.getExtensions()
.create(
"android",
AppExtension.class,
project,
instantiator,
androidBuilder,
sdkHandler,
buildTypeContainer,
productFlavorContainer,
signingConfigContainer,
extraModelInfo);
}
这里也就是可以看到我们android块配置是如何来的了,对应的Extension也确实是AppExtension,继续查看 configureExtension 的源码
dependencyManager = new DependencyManager(
project,
extraModelInfo,
sdkHandler);
ndkHandler = new NdkHandler(
project.getRootDir(),
null, /* compileSkdVersion, this will be set in afterEvaluate */
"gcc",
"" /*toolchainVersion*/);
taskManager =
createTaskManager(
project,
androidBuilder,
dataBindingBuilder,
extension,
sdkHandler,
ndkHandler,
dependencyManager,
registry,
threadRecorder);
variantFactory = createVariantFactory(instantiator, androidBuilder, extension);
variantManager =
new VariantManager(
project,
androidBuilder,
extension,
variantFactory,
taskManager,
instantiator,
threadRecorder);
// Register a builder for the custom tooling model
ModelBuilder modelBuilder = new ModelBuilder(
androidBuilder,
variantManager,
taskManager,
extension,
extraModelInfo,
ndkHandler,
new NativeLibraryFactoryImpl(ndkHandler),
getProjectType(),
AndroidProject.GENERATION_ORIGINAL);
registry.register(modelBuilder);
// Register a builder for the native tooling model
NativeModelBuilder nativeModelBuilder = new NativeModelBuilder(variantManager);
registry.register(nativeModelBuilder);
这一部分主要是创建一些管理类,其中 createTaskManager、createVariantFactory 都是抽象方法,对应的实现类
createTaskManager
AppPlugin -> ApplicationTaskManager
LibraryPlugin -> LibraryTaskManager
createVariantFactory
AppPlugin -> ApplicationVariantFactory
LibraryPlugin -> LibraryVariantFactory
这里简单介绍一下 TaskManager 就是创建具体任务的管理类,app 工程和库 library 工程所需的构建任务是不同的,后面我们会介绍 app 工程创建的构建任务;VariantFactory 就是我们常说的构建变体的工厂类,主要是生成Variant(构建变体)的对象。我们回到 createExtension 的源码中
// map the whenObjectAdded callbacks on the containers.
signingConfigContainer.whenObjectAdded(variantManager::addSigningConfig);
buildTypeContainer.whenObjectAdded(
buildType -> {
SigningConfig signingConfig =
signingConfigContainer.findByName(BuilderConstants.DEBUG);
buildType.init(signingConfig);
variantManager.addBuildType(buildType);
});
productFlavorContainer.whenObjectAdded(variantManager::addProductFlavor);
...
// create default Objects, signingConfig first as its used by the BuildTypes.
variantFactory.createDefaultComponents(
buildTypeContainer, productFlavorContainer, signingConfigContainer);
这一部分做得事情,配置了 BuildTypeContainer、ProductFlavorContainer、SigningConfigContainer 这三个配置项的 whenObjectAdded 的回调,每个配置的添加都会加入到 variantManager 中;创建默认配置,下面是 ApplicationVariantFactory 的 createDefaultComponents 代码
@Override
public void createDefaultComponents(
@NonNull NamedDomainObjectContainer<BuildType> buildTypes,
@NonNull NamedDomainObjectContainer<ProductFlavor> productFlavors,
@NonNull NamedDomainObjectContainer<SigningConfig> signingConfigs) {
// must create signing config first so that build type 'debug' can be initialized
// with the debug signing config.
signingConfigs.create(DEBUG);
buildTypes.create(DEBUG);
buildTypes.create(RELEASE);
}
总结一下 configureExtension 方法的作用,主要是创建 Android 插件的扩展对象,对配置项 BuildType、ProductFlavor、SigningConfig 做了统一的创建和回调处理, 创建taskManager、variantFactory、variantManager。
createTasks
private void createTasks() {
threadRecorder.record(
ExecutionType.TASK_MANAGER_CREATE_TASKS,
project.getPath(),
null,
() -> // 在项目评估之前创建任务
taskManager.createTasksBeforeEvaluate(
new TaskContainerAdaptor(project.getTasks())));
project.afterEvaluate(
project ->
threadRecorder.record(
ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
project.getPath(),
null,
// 在项目评估完成之后创建 androidTask
() -> createAndroidTasks(false)));
}
这里主要是分两块,一个是在 beforeEvaluate 创建任务;一个是在 afterEvaluate 创建任务。这里的区别是 AndroidTask 是依赖配置项的配置才能生成相应任务,所以是需要在 afterEvaluate 之后创建,如果对项目评估回调不理解的话,可以查阅Project文档。beforeEvaluate 创建的任务跟我们编译没有太大关系,我们重点查看一下 afterEvaluate 创建的任务 createAndroidTasks
@VisibleForTesting
final void createAndroidTasks(boolean force) {
...
threadRecorder.record(
ExecutionType.VARIANT_MANAGER_CREATE_ANDROID_TASKS,
project.getPath(),
null,
() -> {
// 创建AndroidTasks
variantManager.createAndroidTasks();
ApiObjectFactory apiObjectFactory =
new ApiObjectFactory(
androidBuilder, extension, variantFactory, instantiator);
for (BaseVariantData variantData : variantManager.getVariantDataList()) {
apiObjectFactory.create(variantData);
}
});
...
}
我们主要看下variantManager的createAndroidTasks的方法
/**
* Variant/Task creation entry point.
*
* Not used by gradle-experimental.
*/
public void createAndroidTasks() {
variantFactory.validateModel(this);
variantFactory.preVariantWork(project);
final TaskFactory tasks = new TaskContainerAdaptor(project.getTasks());
if (variantDataList.isEmpty()) {
recorder.record(
ExecutionType.VARIANT_MANAGER_CREATE_VARIANTS,
project.getPath(),
null /*variantName*/,
this::populateVariantDataList);
}
// Create top level test tasks.
recorder.record(
ExecutionType.VARIANT_MANAGER_CREATE_TESTS_TASKS,
project.getPath(),
null /*variantName*/,
() -> taskManager.createTopLevelTestTasks(tasks, !productFlavors.isEmpty()));
for (final BaseVariantData<? extends BaseVariantOutputData> variantData : variantDataList) {
recorder.record(
ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT,
project.getPath(),
variantData.getName(),
() -> createTasksForVariantData(tasks, variantData));
}
taskManager.createReportTasks(tasks, variantDataList);
}
首先判断 variantDataList 是否是空,如果是空的就会进入到 populateVariantDataList 方法中
/**
* Create all variants.
*/
public void populateVariantDataList() {
if (productFlavors.isEmpty()) {
createVariantDataForProductFlavors(Collections.emptyList());
} else {
List<String> flavorDimensionList = extension.getFlavorDimensionList();
// Create iterable to get GradleProductFlavor from ProductFlavorData.
Iterable<CoreProductFlavor> flavorDsl =
Iterables.transform(
productFlavors.values(),
ProductFlavorData::getProductFlavor);
// Get a list of all combinations of product flavors.
List<ProductFlavorCombo<CoreProductFlavor>> flavorComboList =
ProductFlavorCombo.createCombinations(
flavorDimensionList,
flavorDsl);
for (ProductFlavorCombo<CoreProductFlavor> flavorCombo : flavorComboList) {
//noinspection unchecked
createVariantDataForProductFlavors(
(List<ProductFlavor>) (List) flavorCombo.getFlavorList());
}
}
}
从方法注释可以看到,这个方法主要的作用就是创建所有的 variants,试想一下该段代码会做哪些事情,是否是解析 buildType、productFlavor 配置?
创建构建变体(BuildVariant)
继续观察上面的代码,可以看到无论是否有配置productFlavor 子项,都会进入到 createVariantDataForProductFlavors 方法。如果有配置的话,通过获取配置的 flavorDimension 和 productFlavor 数组,调用 ProductFlavorCombo.createCombinations 组合出最后的产品风味数组 flavorComboList ,最后通过遍历调用 createVariantDataForProductFlavors 方法
/**
* Creates VariantData for a specified list of product flavor.
*
* This will create VariantData for all build types of the given flavors.
*
* @param productFlavorList the flavor(s) to build.
*/
private void createVariantDataForProductFlavors(
@NonNull List<ProductFlavor> productFlavorList) {
...
for (BuildTypeData buildTypeData : buildTypes.values()) {
boolean ignore = false;
...
if (!ignore) {
BaseVariantData<?> variantData = createVariantData(
buildTypeData.getBuildType(),
productFlavorList);
variantDataList.add(variantData);
...
}
}
...
}
看上述代码,通过 creatVariantData 方法,将 buildType 和 productFlavor 的作为参数传入,创建了 variantData,并且加入到了 variantDataList 集合中,这里我们就是将所有的构建变体集合到了 variantDataList 中。
接着我们返回继续看 createAndroidTasks 方法
/**
* Variant/Task creation entry point.
*
* Not used by gradle-experimental.
*/
public void createAndroidTasks() {
...
for (final BaseVariantData<? extends BaseVariantOutputData> variantData : variantDataList) {
recorder.record(
ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT,
project.getPath(),
variantData.getName(),
() -> createTasksForVariantData(tasks, variantData));
}
...
}
通过上面拿到的variantDataList,遍历该集合来创建任务
/**
* Create tasks for the specified variantData.
*/
public void createTasksForVariantData(
final TaskFactory tasks,
final BaseVariantData<? extends BaseVariantOutputData> variantData) {
final BuildTypeData buildTypeData = buildTypes.get(
variantData.getVariantConfiguration().getBuildType().getName());
if (buildTypeData.getAssembleTask() == null) {
// 创建assemble + buildType任务
buildTypeData.setAssembleTask(taskManager.createAssembleTask(tasks, buildTypeData));
}
// Add dependency of assemble task on assemble build type task.
tasks.named("assemble", new Action<Task>() {
@Override
public void execute(Task task) {
assert buildTypeData.getAssembleTask() != null;
// 将 assemble 任务依赖于我们的 assemble + buildType 任务
task.dependsOn(buildTypeData.getAssembleTask().getName());
}
});
VariantType variantType = variantData.getType();
// 根据 variantData 创建 assemble + flavor + buildType 任务
createAssembleTaskForVariantData(tasks, variantData);
if (variantType.isForTesting()) {
...
} else {
// 根据 variantData 创建一系列任务
taskManager.createTasksForVariantData(tasks, variantData);
}
}
首先会先根据 buildType 信息创建 assemble + buildType 的任务,可以看下taskManager. createAssembleTask里的代码
@NonNull
public AndroidTask<DefaultTask> createAssembleTask(
@NonNull TaskFactory tasks,
@NonNull VariantDimensionData dimensionData) {
final String sourceSetName =
StringHelper.capitalize(dimensionData.getSourceSet().getName());
return androidTasks.create(
tasks,
// 设置任务名字为 assembleXXX
"assemble" + sourceSetName,
assembleTask -> {
// 设置描述和任务组
assembleTask.setDescription("Assembles all " + sourceSetName + " builds.");
assembleTask.setGroup(BasePlugin.BUILD_GROUP);
});
}
创建完任务之后,将assemble任务依赖于我们的assembleXXX任务,随后调用 createAssembleTaskForVariantData 方法,此方法是创建 assemble + flavor + buildType 任务,流程多了 productFlavor 任务的创建,这里就不赘述了。后面会执 createTasksForVariantData,这个方法就是根据 variant 生成一系列 Android 构建所需任务(后面会详细介绍),回到 createAndroidTasks 方法中
threadRecorder.record(
ExecutionType.VARIANT_MANAGER_CREATE_ANDROID_TASKS,
project.getPath(),
null,
() -> {
variantManager.createAndroidTasks();
ApiObjectFactory apiObjectFactory =
new ApiObjectFactory(
androidBuilder, extension, variantFactory, instantiator);
for (BaseVariantData variantData : variantManager.getVariantDataList()) {
// 创建variantApi,添加到extensions中
apiObjectFactory.create(variantData);
}
});
最后就遍历 variantDataList 通过 ApiObjectFactory 创建 variantApi,添加到 extensions 中。至此,我们就已经将配置的构建变种任务已经添加到我们的任务列表中,并形成了相关依赖。
一篇文太长,还有一半下一章发出来。
最后
感谢你到这里,喜欢的话请帮忙点个赞让更多需要的人看到哦。更多Android进阶技术,面试资料整理分享,职业生涯规划,产品,思维,行业观察,谈天说地。可以加Android架构师群;701740775。