本文是根据gradle3.1.2源码进行分析。Android Gradle Plugin本质上是一个gradle插件,肯定遵循自定义插件的结构,即继承Plugin类的源码,resources目录结构等。为简便起见,以下都将Android Gradle Plugin简称为AGP。
在分析源码之前,我们需要先下载AGP的源码。我们在此链接手动下载AGP3.1.2的源码。
Gradle 3.1.2源码的大概设计
androidGradle.png- Extension:定义DSL类
- Plugin:插件的入口
- TaskManager:负责创建Task,本质上调用TaskContainer#create
- Tasks:具体的任务类
- Processor:处理具体的任务类
- 工具:真正的执行者
分析AppPlugin
我们在创建一个Android新项目时,项目模块的build.gradle文件中的第一行往往都是apply plugin: 'com.android.application'
这行代码。这行代码会调用com.android.application
插件的apply方法。
我们打开AGP源码的resources目录下的com.android.application.properties
文件。其内容为implementation-class=com.android.build.gradle.AppPlugin
因此,我们从AppPlugin类的apply方法开始分析。
apply.pngpublic class AppPlugin extends BasePlugin<AppExtensionImpl> {
...
@Override
public void apply(@NonNull Project project) {
super.apply(project);
}
}
AppPlugin#apply方法很简单,只是调用父类BasePlugin#apply的方法。我们继续查看BasePlugin#apply。
@Override
public void apply(@NonNull Project project) {
// We run by default in headless mode, so the JVM doesn't steal focus.
System.setProperty("java.awt.headless", "true");
this.project = project;
this.projectOptions = new ProjectOptions(project);
project.getPluginManager().apply(AndroidBasePlugin.class);
checkConfigureOnDemandGradleVersionCompat();
checkPathForErrors();
checkModulesForErrors();
PluginInitializer.initialize(project);
ProfilerInitializer.init(project, projectOptions);
threadRecorder = ThreadRecorder.get();
ProcessProfileWriter.getProject(project.getPath())
.setAndroidPluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION)
.setAndroidPlugin(getAnalyticsPluginType())
.setPluginGeneration(GradleBuildProject.PluginGeneration.FIRST)
.setOptions(AnalyticsUtil.toProto(projectOptions));
BuildableArtifactImpl.Companion.disableResolution();
if (!projectOptions.get(BooleanOption.ENABLE_NEW_DSL_AND_API)) {
TaskInputHelper.enableBypass();
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);
} else {
// 代码省略
}
}
上述代码中,依次执行configureProject,configureExtension,createTasks方法。
下面我们将依次分析这三个方法。
BasePlugin#configureProject
private void configureProject() {
final Gradle gradle = project.getGradle();
extraModelInfo = new ExtraModelInfo(project.getPath(), projectOptions, project.getLogger());
// 检查Gradle版本,如果Gradle版本低于所要求的最低版本,
// 则抛出异常。gradle3.1.2要求gradle版本最低为4.4
checkGradleVersion(project, getLogger(), projectOptions);
sdkHandler = new SdkHandler(project, getLogger());
// 省略代码
androidBuilder =
new AndroidBuilder(
project == project.getRootProject() ? project.getName() : project.getPath(),
creator,
new GradleProcessExecutor(project),
new GradleJavaProcessExecutor(project),
extraModelInfo.getSyncIssueHandler(),
extraModelInfo.getMessageReceiver(),
getLogger(),
isVerbose());
dataBindingBuilder = new DataBindingBuilder();
dataBindingBuilder.setPrintMachineReadableOutput(
SyncOptions.getErrorFormatMode(projectOptions) == ErrorFormatMode.MACHINE_PARSABLE);
// 检查是否有被移除的配置选项
if (projectOptions.hasRemovedOptions()) {
androidBuilder
.getIssueReporter()
.reportWarning(Type.GENERIC, projectOptions.getRemovedOptionsErrorMessage());
}
// 检查是否使用被弃用的配置选项
if (projectOptions.hasDeprecatedOptions()) {
extraModelInfo
.getDeprecationReporter()
.reportDeprecatedOptions(projectOptions.getDeprecatedOptions());
}
// Apply the Java plugin
project.getPlugins().apply(JavaBasePlugin.class);
project.getTasks()
.getByName("assemble")
.setDescription(
"Assembles all variants of all applications and secondary packages.");
// 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.
gradle.addBuildListener(
new BuildListener() {
@Override
public void buildStarted(@NonNull Gradle gradle) {
TaskInputHelper.enableBypass();
BuildableArtifactImpl.Companion.disableResolution();
}
@Override
public void settingsEvaluated(@NonNull Settings settings) {}
@Override
public void projectsLoaded(@NonNull Gradle gradle) {}
@Override
public void projectsEvaluated(@NonNull Gradle gradle) {}
@Override
public void buildFinished(@NonNull BuildResult buildResult) {
// Do not run buildFinished for included project in composite build.
if (buildResult.getGradle().getParent() != null) {
return;
}
sdkHandler.unload();
threadRecorder.record(
ExecutionType.BASE_PLUGIN_BUILD_FINISHED,
project.getPath(),
null,
() -> {
WorkerActionServiceRegistry.INSTANCE
.shutdownAllRegisteredServices(
ForkJoinPool.commonPool());
PreDexCache.getCache()
.clear(
FileUtils.join(
project.getRootProject().getBuildDir(),
FD_INTERMEDIATES,
"dex-cache",
"cache.xml"),
getLogger());
Main.clearInternTables();
});
}
});
gradle.getTaskGraph()
.addTaskExecutionGraphListener(
taskGraph -> {
TaskInputHelper.disableBypass();
Aapt2DaemonManagerService.registerAaptService(
Objects.requireNonNull(androidBuilder.getTargetInfo())
.getBuildTools(),
loggerWrapper,
WorkerActionServiceRegistry.INSTANCE);
for (Task task : taskGraph.getAllTasks()) {
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;
}
}
}
});
createLintClasspathConfiguration(project);
}
从上面代码可以看出,该方法前面主要做一些gradle版本检查,以及配置选项是否被弃用等等,诸如此类的工作。
BasePlugin#configureExtension
private void configureExtension() {
ObjectFactory objectFactory = project.getObjects();
final NamedDomainObjectContainer<BuildType> buildTypeContainer =
project.container(
BuildType.class,
new BuildTypeFactory(
objectFactory,
project,
extraModelInfo.getSyncIssueHandler(),
extraModelInfo.getDeprecationReporter()));
final NamedDomainObjectContainer<ProductFlavor> productFlavorContainer =
project.container(
ProductFlavor.class,
new ProductFlavorFactory(
objectFactory,
project,
extraModelInfo.getDeprecationReporter(),
project.getLogger()));
final NamedDomainObjectContainer<SigningConfig> signingConfigContainer =
project.container(
SigningConfig.class,
new SigningConfigFactory(
objectFactory,
GradleKeystoreHelper.getDefaultDebugKeystoreLocation()));
final NamedDomainObjectContainer<BaseVariantOutput> buildOutputs =
project.container(BaseVariantOutput.class);
project.getExtensions().add("buildOutputs", buildOutputs);
sourceSetManager = createSourceSetManager();
extension =
createExtension(
project,
projectOptions,
androidBuilder,
sdkHandler,
buildTypeContainer,
productFlavorContainer,
signingConfigContainer,
buildOutputs,
sourceSetManager,
extraModelInfo);
ndkHandler =
new NdkHandler(
project.getRootDir(),
null, /* compileSkdVersion, this will be set in afterEvaluate */
"gcc",
"" /*toolchainVersion*/,
false /* useUnifiedHeaders */);
@Nullable
FileCache buildCache = BuildCacheUtils.createBuildCacheIfEnabled(project, projectOptions);
GlobalScope globalScope =
new GlobalScope(
project,
projectOptions,
androidBuilder,
extension,
sdkHandler,
ndkHandler,
registry,
buildCache);
variantFactory = createVariantFactory(globalScope, androidBuilder, extension);
taskManager =
createTaskManager(
globalScope,
project,
projectOptions,
androidBuilder,
dataBindingBuilder,
extension,
sdkHandler,
ndkHandler,
registry,
threadRecorder);
variantManager =
new VariantManager(
globalScope,
project,
projectOptions,
androidBuilder,
extension,
variantFactory,
taskManager,
sourceSetManager,
threadRecorder);
registerModels(registry, globalScope, variantManager, extension, extraModelInfo);
// 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);
// map whenObjectRemoved on the containers to throw an exception.
signingConfigContainer.whenObjectRemoved(
new UnsupportedAction("Removing signingConfigs is not supported."));
buildTypeContainer.whenObjectRemoved(
new UnsupportedAction("Removing build types is not supported."));
productFlavorContainer.whenObjectRemoved(
new UnsupportedAction("Removing product flavors is not supported."));
// create default Objects, signingConfig first as its used by the BuildTypes.
variantFactory.createDefaultComponents(
buildTypeContainer, productFlavorContainer, signingConfigContainer);
}
该方法主要是创建Extension,并且创建相应的TaskManager和VariantManager。AppPlugin对应的Extension是AppExtension,对应的TaskManager是ApplicationTaskManager。
然后依次添加signingConfig,buildType和productFlavor。主要通过调用Variant Manager的addSigningConfig,addBuildType以及addProductFlavor方法。
BasePlugin#createTasks
private void createTasks() {
threadRecorder.record(
ExecutionType.TASK_MANAGER_CREATE_TASKS,
project.getPath(),
null,
() -> taskManager.createTasksBeforeEvaluate());
project.afterEvaluate(
project ->
threadRecorder.record(
ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
project.getPath(),
null,
() -> createAndroidTasks(false)));
}
BasePlugin#createAndroidTasks
@VisibleForTesting
final void createAndroidTasks(boolean force) {
// Make sure unit tests set the required fields.
checkState(extension.getBuildToolsRevision() != null,
"buildToolsVersion is not specified.");
checkState(extension.getCompileSdkVersion() != null, "compileSdkVersion is not specified.");
ndkHandler.setCompileSdkVersion(extension.getCompileSdkVersion());
// get current plugins and look for the default Java plugin.
if (project.getPlugins().hasPlugin(JavaPlugin.class)) {
throw new BadPluginException(
"The 'java' plugin has been applied, but it is not compatible with the Android plugins.");
}
boolean targetSetupSuccess = ensureTargetSetup();
sdkHandler.ensurePlatformToolsIsInstalledWarnOnFailure(
extraModelInfo.getSyncIssueHandler());
// Stop trying to configure the project if the SDK is not ready.
// Sync issues will already have been collected at this point in sync.
if (!targetSetupSuccess) {
project.getLogger()
.warn("Aborting configuration as SDK is missing components in sync mode.");
return;
}
// don't do anything if the project was not initialized.
// Unless TEST_SDK_DIR is set in which case this is unit tests and we don't return.
// This is because project don't get evaluated in the unit test setup.
// See AppPluginDslTest
if (!force
&& (!project.getState().getExecuted() || project.getState().getFailure() != null)
&& SdkHandler.sTestSdkFolder == null) {
return;
}
if (hasCreatedTasks) {
return;
}
hasCreatedTasks = true;
extension.disableWrite();
taskManager.configureCustomLintChecks();
ProcessProfileWriter.getProject(project.getPath())
.setCompileSdk(extension.getCompileSdkVersion())
.setBuildToolsVersion(extension.getBuildToolsRevision().toString())
.setSplits(AnalyticsUtil.toProto(extension.getSplits()));
String kotlinPluginVersion = getKotlinPluginVersion();
if (kotlinPluginVersion != null) {
ProcessProfileWriter.getProject(project.getPath())
.setKotlinPluginVersion(kotlinPluginVersion);
}
// setup SDK repositories.
sdkHandler.addLocalRepositories(project);
threadRecorder.record(
ExecutionType.VARIANT_MANAGER_CREATE_ANDROID_TASKS,
project.getPath(),
null,
() -> {
variantManager.createAndroidTasks();
ApiObjectFactory apiObjectFactory =
new ApiObjectFactory(
androidBuilder,
extension,
variantFactory,
project.getObjects());
for (VariantScope variantScope : variantManager.getVariantScopes()) {
BaseVariantData variantData = variantScope.getVariantData();
apiObjectFactory.create(variantData);
}
// Make sure no SourceSets were added through the DSL without being properly configured
// Only do it if we are not restricting to a single variant (with Instant
// Run or we can find extra source set
if (projectOptions.get(StringOption.IDE_RESTRICT_VARIANT_NAME) == null) {
sourceSetManager.checkForUnconfiguredSourceSets();
}
// must run this after scopes are created so that we can configure kotlin
// kapt tasks
taskManager.addDataBindingDependenciesIfNecessary(
extension.getDataBinding(), variantManager.getVariantScopes());
});
// create the global lint task that depends on all the variants
taskManager.configureGlobalLintTask(variantManager.getVariantScopes());
// Create and read external native build JSON files depending on what's happening right
// now.
//
// CREATE PHASE:
// Creates JSONs by shelling out to external build system when:
// - Any one of AndroidProject.PROPERTY_INVOKED_FROM_IDE,
// AndroidProject.PROPERTY_BUILD_MODEL_ONLY_ADVANCED,
// AndroidProject.PROPERTY_BUILD_MODEL_ONLY,
// AndroidProject.PROPERTY_REFRESH_EXTERNAL_NATIVE_MODEL are set.
// - *and* AndroidProject.PROPERTY_REFRESH_EXTERNAL_NATIVE_MODEL is set
// or JSON files don't exist or are out-of-date.
// Create phase may cause ProcessException (from cmake.exe for example)
//
// READ PHASE:
// Reads and deserializes JSONs when:
// - Any one of AndroidProject.PROPERTY_INVOKED_FROM_IDE,
// AndroidProject.PROPERTY_BUILD_MODEL_ONLY_ADVANCED,
// AndroidProject.PROPERTY_BUILD_MODEL_ONLY,
// AndroidProject.PROPERTY_REFRESH_EXTERNAL_NATIVE_MODEL are set.
// Read phase may produce IOException if the file can't be read for standard IO reasons.
// Read phase may produce JsonSyntaxException in the case that the content of the file is
// corrupt.
boolean forceRegeneration =
projectOptions.get(BooleanOption.IDE_REFRESH_EXTERNAL_NATIVE_MODEL);
checkSplitConfiguration();
if (ExternalNativeBuildTaskUtils.shouldRegenerateOutOfDateJsons(projectOptions)) {
threadRecorder.record(
ExecutionType.VARIANT_MANAGER_EXTERNAL_NATIVE_CONFIG_VALUES,
project.getPath(),
null,
() -> {
for (VariantScope variantScope : variantManager.getVariantScopes()) {
ExternalNativeJsonGenerator generator =
variantScope.getExternalNativeJsonGenerator();
if (generator != null) {
// This will generate any out-of-date or non-existent JSONs.
// When refreshExternalNativeModel() is true it will also
// force update all JSONs.
generator.build(forceRegeneration);
}
}
});
}
BuildableArtifactImpl.Companion.enableResolution();
}
VariantManager#createAndroidTasks
public void createAndroidTasks() {
variantFactory.validateModel(this);
variantFactory.preVariantWork(project);
if (variantScopes.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(!productFlavors.isEmpty()));
for (final VariantScope variantScope : variantScopes) {
recorder.record(
ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT,
project.getPath(),
variantScope.getFullVariantName(),
() -> createTasksForVariantData(variantScope));
}
taskManager.createReportTasks(variantScopes);
}
该方法是创建变体和任务的入口。首先,判断variantScopes变量是否为空。variantScopes变量是VariantScope的List。而VariantScope是存放特定变体的数据。如果variantScopes为空,则会调用populateVariantDataList方法。populateVariantDataList方法用于创建所有的变体。现在我们查看一下populateVariantDataList方法如何创建变体的。
VariantManager#populateVariantDataList
public void populateVariantDataList() {
List<String> flavorDimensionList = extension.getFlavorDimensionList();
if (productFlavors.isEmpty()) {
configureDependencies();
createVariantDataForProductFlavors(Collections.emptyList());
} else {
// ensure that there is always a dimension
if (flavorDimensionList == null || flavorDimensionList.isEmpty()) {
androidBuilder
.getIssueReporter()
.reportError(
EvalIssueReporter.Type.UNNAMED_FLAVOR_DIMENSION,
"All flavors must now belong to a named flavor dimension. "
+ "Learn more at "
+ "https://d.android.com/r/tools/flavorDimensions-missing-error-message.html");
} else if (flavorDimensionList.size() == 1) {
// if there's only one dimension, auto-assign the dimension to all the flavors.
String dimensionName = flavorDimensionList.get(0);
for (ProductFlavorData<CoreProductFlavor> flavorData : productFlavors.values()) {
CoreProductFlavor flavor = flavorData.getProductFlavor();
if (flavor.getDimension() == null && flavor instanceof DefaultProductFlavor) {
((DefaultProductFlavor) flavor).setDimension(dimensionName);
}
}
}
// can only call this after we ensure all flavors have a dimension.
configureDependencies();
// 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());
}
}
}
首先,通过extension变量获得变体的风味维度(即flavor dimension),然后,判断productFlavors是否为空,若为空,则调用configureDependencies和createVariantDataForProductFlavors方法。若不为空,则判断flavorDimensionList是否为null,若为null,则报告错误。如果你之前升级过gradle3.0,那么对这个报错信息肯定很熟悉。它提示你,所有的flavors都必须有一个维度,即dimension。dimension是Gradle3.0以上新加的特性。具体的内容可以见升级Gradle3.x文章。
分析完populateVariantDataList方法后,我们继续看VariantManager#createAndroidTasks 方法的执行过程。主要先后调用三个方法,createTopLevelTestTasks,createTasksForVariantData以及createReportTasks方法。createTopLevelTestTasks主要是用来创建一些测试任务,在这里就不具体分析了,有兴趣的可以自行查看源码。下面我们主要分析一下createTasksForVariantData方法。
VariantManager#createTasksForVariantData
/** Create tasks for the specified variant. */
public void createTasksForVariantData(final VariantScope variantScope) {
final BaseVariantData variantData = variantScope.getVariantData();
final VariantType variantType = variantData.getType();
final GradleVariantConfiguration variantConfig = variantScope.getVariantConfiguration();
final BuildTypeData buildTypeData = buildTypes.get(variantConfig.getBuildType().getName());
if (buildTypeData.getAssembleTask() == null) {
buildTypeData.setAssembleTask(taskManager.createAssembleTask(buildTypeData));
}
// Add dependency of assemble task on assemble build type task.
taskManager
.getTaskFactory()
.configure(
"assemble",
task -> {
assert buildTypeData.getAssembleTask() != null;
task.dependsOn(buildTypeData.getAssembleTask().getName());
});
createAssembleTaskForVariantData(variantData);
if (variantType.isForTesting()) {
// 省略代码
} else {
taskManager.createTasksForVariantScope(variantScope);
}
}
VariantManager类主要用于创建和管理变体。这个方法主要作用是创建变体的task。主要是将variantScope参数传给TaskManager的createTasksForVariantScope方法。createTasksForVariantScope方法逻辑很简单,在非测试环境下,直接调用TaskManager的createTasksForVariantScope方法。上面我们说过,AppPlugin的TaskManger实现类是ApplicationTaskManager。我们将代码定位到ApplicationTaskManager类的createTasksForVariantScope方法。
ApplicationTaskManager#createTasksForVariantScope
@Override
public void createTasksForVariantScope(@NonNull final VariantScope variantScope) {
BaseVariantData variantData = variantScope.getVariantData();
assert variantData instanceof ApplicationVariantData;
// 这个方法会创建preBuild任务
createAnchorTasks(variantScope);
createCheckManifestTask(variantScope);
// 这个主要是针对可穿戴设备
// Configure variantData to generate embedded wear application.
handleMicroApp(variantScope);
// Create all current streams (dependencies mostly at this point)
createDependencyStreams(variantScope);
// Add a task to publish the applicationId.
createApplicationIdWriterTask(variantScope);
taskFactory.create(new MainApkListPersistence.ConfigAction(variantScope));
taskFactory.create(new BuildArtifactReportTask.ConfigAction(variantScope));
// Add a task to process the manifest(s)
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_MANIFEST_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createMergeApkManifestsTask(variantScope));
// Add a task to create the res values
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_GENERATE_RES_VALUES_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createGenerateResValuesTask(variantScope));
// Add a task to compile renderscript files.
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_CREATE_RENDERSCRIPT_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createRenderscriptTask(variantScope));
// Add a task to merge the resource folders
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_RESOURCES_TASK,
project.getPath(),
variantScope.getFullVariantName(),
(Recorder.VoidBlock) () -> createMergeResourcesTask(variantScope, true));
// Add tasks to compile shader
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_SHADER_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createShaderTask(variantScope));
// Add a task to merge the asset folders
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_ASSETS_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> {
createMergeAssetsTask(variantScope);
});
// Add a task to create the BuildConfig class
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_BUILD_CONFIG_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createBuildConfigTask(variantScope));
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_PROCESS_RES_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> {
// Add a task to process the Android Resources and generate source files
createApkProcessResTask(variantScope);
// Add a task to process the java resources
createProcessJavaResTask(variantScope);
});
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_AIDL_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createAidlTask(variantScope));
// Add NDK tasks
if (!isComponentModelPlugin()) {
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_NDK_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createNdkTasks(variantScope));
} else {
if (variantData.compileTask != null) {
variantData.compileTask.dependsOn(getNdkBuildable(variantData));
} else {
variantScope.getCompileTask().dependsOn(getNdkBuildable(variantData));
}
}
variantScope.setNdkBuildable(getNdkBuildable(variantData));
// Add external native build tasks
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_EXTERNAL_NATIVE_BUILD_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> {
createExternalNativeBuildJsonGenerators(variantScope);
createExternalNativeBuildTasks(variantScope);
});
// Add a task to merge the jni libs folders
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_JNILIBS_FOLDERS_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createMergeJniLibFoldersTasks(variantScope));
// Add data binding tasks if enabled
createDataBindingTasksIfNecessary(variantScope, MergeType.MERGE);
// Add a compile task
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_COMPILE_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> addCompileTask(variantScope));
createStripNativeLibraryTask(taskFactory, variantScope);
if (variantScope.getVariantData().getMultiOutputPolicy().equals(MultiOutputPolicy.SPLITS)) {
if (extension.getBuildToolsRevision().getMajor() < 21) {
throw new RuntimeException(
"Pure splits can only be used with buildtools 21 and later");
}
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_SPLIT_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createSplitTasks(variantScope));
}
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_PACKAGING_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> {
BuildInfoWriterTask buildInfoWriterTask =
createInstantRunPackagingTasks(variantScope);
createPackagingTask(variantScope, buildInfoWriterTask);
});
// create the lint tasks.
recorder.record(
ExecutionType.APP_TASK_MANAGER_CREATE_LINT_TASK,
project.getPath(),
variantScope.getFullVariantName(),
() -> createLintTasks(variantScope));
}
在上述代码中看到,大部分的任务都是在createTasksForVariantScope方法里使用taskFactory创建的。taskFactory是TaskFactory接口的对象。TaskFactory的实现类是TaskFactoryImp。
我们运行一个Android工程的assembleRelease任务,就可以看到任务的执行顺序,如下所示:
:app:preBuild UP-TO-DATE
:app:preReleaseBuild
:app:compileReleaseAidl
:app:compileReleaseRenderscript
:app:checkReleaseManifest
:app:generateReleaseBuildConfig
:app:prepareLintJar UP-TO-DATE
:app:mainApkListPersistenceRelease
:app:generateReleaseResValues
:app:generateReleaseResources
:app:mergeReleaseResources
:app:createReleaseCompatibleScreenManifests
:app:processReleaseManifest
:app:splitsDiscoveryTaskRelease
:app:processReleaseResources
:app:generateReleaseSources
:app:javaPreCompileRelease
:app:compileReleaseJavaWithJavac
:app:compileReleaseNdk NO-SOURCE
:app:compileReleaseSources
:app:lintVitalRelease
:app:mergeReleaseShaders
:app:compileReleaseShaders
:app:generateReleaseAssets
:app:mergeReleaseAssets
:app:transformClassesWithDexBuilderForRelease
:app:transformDexArchiveWithExternalLibsDexMergerForRelease
:app:transformDexArchiveWithDexMergerForRelease
:app:mergeReleaseJniLibFolders
:app:transformNativeLibsWithMergeJniLibsForRelease
:app:transformNativeLibsWithStripDebugSymbolForRelease
:app:processReleaseJavaRes NO-SOURCE
:app:transformResourcesWithMergeJavaResForRelease
:app:packageRelease
:app:assembleRelease
总结
本篇文章主要分析了Android Gradle3.1.2插件的源码大体设计,以及如何通过apply plugin: 'com.android.application'创建了变体和任务的。
在下一篇文章,会继续分析具体Task的执行过程。
网友评论