本文是根據(jù)gradle3.1.2源碼進(jìn)行分析呀页。Android Gradle Plugin本質(zhì)上是一個(gè)gradle插件妈拌,肯定遵循自定義插件的結(jié)構(gòu),即繼承Plugin類的源碼蓬蝶,resources目錄結(jié)構(gòu)等尘分。為簡(jiǎn)便起見,以下都將Android Gradle Plugin簡(jiǎn)稱為AGP丸氛。
在分析源碼之前培愁,我們需要先下載AGP的源碼。我們?cè)?a target="_blank" rel="nofollow">此鏈接手動(dòng)下載AGP3.1.2的源碼缓窜。
Gradle 3.1.2源碼的大概設(shè)計(jì)
- Extension:定義DSL類
- Plugin:插件的入口
- TaskManager:負(fù)責(zé)創(chuàng)建Task定续,本質(zhì)上調(diào)用TaskContainer#create
- Tasks:具體的任務(wù)類
- Processor:處理具體的任務(wù)類
- 工具:真正的執(zhí)行者
分析AppPlugin
我們?cè)趧?chuàng)建一個(gè)Android新項(xiàng)目時(shí),項(xiàng)目模塊的build.gradle文件中的第一行往往都是apply plugin: 'com.android.application'
這行代碼禾锤。這行代碼會(huì)調(diào)用com.android.application
插件的apply方法私股。
我們打開AGP源碼的resources目錄下的com.android.application.properties
文件。其內(nèi)容為implementation-class=com.android.build.gradle.AppPlugin
因此时肿,我們從AppPlugin類的apply方法開始分析庇茫。
public class AppPlugin extends BasePlugin<AppExtensionImpl> {
...
@Override
public void apply(@NonNull Project project) {
super.apply(project);
}
}
AppPlugin#apply方法很簡(jiǎn)單港粱,只是調(diào)用父類BasePlugin#apply的方法螃成。我們繼續(xù)查看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 {
// 代碼省略
}
}
上述代碼中查坪,依次執(zhí)行configureProject寸宏,configureExtension,createTasks方法偿曙。
下面我們將依次分析這三個(gè)方法氮凝。
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);
// 檢查是否有被移除的配置選項(xiàng)
if (projectOptions.hasRemovedOptions()) {
androidBuilder
.getIssueReporter()
.reportWarning(Type.GENERIC, projectOptions.getRemovedOptionsErrorMessage());
}
// 檢查是否使用被棄用的配置選項(xiàng)
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版本檢查,以及配置選項(xiàng)是否被棄用等等稿壁,諸如此類的工作幽钢。
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);
}
該方法主要是創(chuàng)建Extension,并且創(chuàng)建相應(yīng)的TaskManager和VariantManager傅是。AppPlugin對(duì)應(yīng)的Extension是AppExtension匪燕,對(duì)應(yīng)的TaskManager是ApplicationTaskManager。
然后依次添加signingConfig喧笔,buildType和productFlavor帽驯。主要通過調(diào)用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);
}
該方法是創(chuàng)建變體和任務(wù)的入口尼变。首先,判斷variantScopes變量是否為空浆劲。variantScopes變量是VariantScope的List享甸。而VariantScope是存放特定變體的數(shù)據(jù)。如果variantScopes為空梳侨,則會(huì)調(diào)用populateVariantDataList方法蛉威。populateVariantDataList方法用于創(chuàng)建所有的變體。現(xiàn)在我們查看一下populateVariantDataList方法如何創(chuàng)建變體的走哺。
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變量獲得變體的風(fēng)味維度(即flavor dimension),然后丙躏,判斷productFlavors是否為空择示,若為空,則調(diào)用configureDependencies和createVariantDataForProductFlavors方法晒旅。若不為空栅盲,則判斷flavorDimensionList是否為null,若為null废恋,則報(bào)告錯(cuò)誤谈秫。如果你之前升級(jí)過gradle3.0,那么對(duì)這個(gè)報(bào)錯(cuò)信息肯定很熟悉鱼鼓。它提示你拟烫,所有的flavors都必須有一個(gè)維度,即dimension迄本。dimension是Gradle3.0以上新加的特性硕淑。具體的內(nèi)容可以見升級(jí)Gradle3.x文章。
分析完populateVariantDataList方法后,我們繼續(xù)看VariantManager#createAndroidTasks 方法的執(zhí)行過程置媳。主要先后調(diào)用三個(gè)方法于樟,createTopLevelTestTasks,createTasksForVariantData以及createReportTasks方法拇囊。createTopLevelTestTasks主要是用來(lái)創(chuàng)建一些測(cè)試任務(wù)隔披,在這里就不具體分析了,有興趣的可以自行查看源碼寂拆。下面我們主要分析一下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類主要用于創(chuàng)建和管理變體。這個(gè)方法主要作用是創(chuàng)建變體的task纠永。主要是將variantScope參數(shù)傳給TaskManager的createTasksForVariantScope方法鬓长。createTasksForVariantScope方法邏輯很簡(jiǎn)單,在非測(cè)試環(huán)境下尝江,直接調(diào)用TaskManager的createTasksForVariantScope方法涉波。上面我們說(shuō)過,AppPlugin的TaskManger實(shí)現(xiàn)類是ApplicationTaskManager炭序。我們將代碼定位到ApplicationTaskManager類的createTasksForVariantScope方法啤覆。
ApplicationTaskManager#createTasksForVariantScope
@Override
public void createTasksForVariantScope(@NonNull final VariantScope variantScope) {
BaseVariantData variantData = variantScope.getVariantData();
assert variantData instanceof ApplicationVariantData;
// 這個(gè)方法會(huì)創(chuàng)建preBuild任務(wù)
createAnchorTasks(variantScope);
createCheckManifestTask(variantScope);
// 這個(gè)主要是針對(duì)可穿戴設(shè)備
// 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));
}
在上述代碼中看到,大部分的任務(wù)都是在createTasksForVariantScope方法里使用taskFactory創(chuàng)建的惭聂。taskFactory是TaskFactory接口的對(duì)象窗声。TaskFactory的實(shí)現(xiàn)類是TaskFactoryImp。
我們運(yùn)行一個(gè)Android工程的assembleRelease任務(wù)辜纲,就可以看到任務(wù)的執(zhí)行順序笨觅,如下所示:
: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
總結(jié)
本篇文章主要分析了Android Gradle3.1.2插件的源碼大體設(shè)計(jì),以及如何通過apply plugin: 'com.android.application'創(chuàng)建了變體和任務(wù)的耕腾。
在下一篇文章见剩,會(huì)繼續(xù)分析具體Task的執(zhí)行過程。