前言
在使用 Android Studio 以后,基本新的 Android 项目都是用 Gradle 作为构建工具,关于 Gradle 的介绍不在本文范畴,当新建一个 Android 项目时,默认只会有个 module 使用com.android.application
插件,Gradle 的核心在于 task,即从 java 源文件和资源文件编译成 apk 文件(编译过程),就是由一系列的 task 组成,task 可以相互依赖,比如最基本的 Task.dependsOn()
,所以理解 Android 编译过程就是理解各个 task 的作用。
本文涉及的源码:
- com.android.tools.build:gradle:3.1.4
- gradle-api-4.4
AppPlugin
com.android.application
的源码位于 com.android.build.gradle.AppPlugin
,AppPlugin 继承于 BasePlugin,BasePlugin 封装了大部分通用的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @Override public void apply(@NonNull Project project) { 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 { } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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))); }
|
从 createTasks()
可以看到,createAndroidTasks()
是在 afterEvaluate()
中执行的,evaluate 是 Gradle 一个执行的过程
Gradle 编译的三个阶段:Initialization、Configuration、Execution。具体可以阅读 build_lifecycle
createAndroidTasks()
这个方法较长,但是我们关心的是 VariantManager.createAndroidTasks()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public void createAndroidTasks() { variantFactory.validateModel(this); variantFactory.preVariantWork(project); if (variantScopes.isEmpty()) { recorder.record( ExecutionType.VARIANT_MANAGER_CREATE_VARIANTS, project.getPath(), null , this::populateVariantDataList); } recorder.record( ExecutionType.VARIANT_MANAGER_CREATE_TESTS_TASKS, project.getPath(), null , () -> 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); }
|
调用 populateVariantDataList()
来生成 VariantScopes,它是由 ProductFlavors、BuildType、VariantType 组合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 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)); } taskManager .getTaskFactory() .configure( "assemble", task -> { assert buildTypeData.getAssembleTask() != null; task.dependsOn(buildTypeData.getAssembleTask().getName()); }); createAssembleTaskForVariantData(variantData); if (variantType.isForTesting()) { } else { taskManager.createTasksForVariantScope(variantScope); } }
|
assemble task 用于将源文件编译为最终产物,比如 jar、aar、apk 等,在 createTasksForVariantData()
中会生成对应 BuildType 的 assemble task,比如 assembleDebug
和 assembleRelease
,接着设置 assemble
依赖于这两个 task,最后根据 variant 生成对应的 assemble task,比如 assembleTestDebug
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| private void createAssembleTaskForVariantData(final BaseVariantData variantData) { final VariantScope variantScope = variantData.getScope(); if (variantData.getType().isForTesting()) { variantScope.setAssembleTask(taskManager.createAssembleTask(variantData)); } else { BuildTypeData buildTypeData = buildTypes.get(variantData.getVariantConfiguration().getBuildType().getName()); Preconditions.checkNotNull(buildTypeData.getAssembleTask()); if (productFlavors.isEmpty()) { variantScope.setAssembleTask(buildTypeData.getAssembleTask()); variantData.addTask( TaskContainer.TaskKind.ASSEMBLE, buildTypeData.getAssembleTask()); } else { variantScope.setAssembleTask(taskManager.createAssembleTask(variantData)); buildTypeData.getAssembleTask().dependsOn(variantScope.getAssembleTask()); GradleVariantConfiguration variantConfig = variantData.getVariantConfiguration(); for (CoreProductFlavor flavor : variantConfig.getProductFlavors()) { ProductFlavorData productFlavorData = productFlavors.get(flavor.getName()); DefaultTask flavorAssembleTask = productFlavorData.getAssembleTask(); if (flavorAssembleTask == null) { flavorAssembleTask = taskManager.createAssembleTask(productFlavorData); productFlavorData.setAssembleTask(flavorAssembleTask); } flavorAssembleTask.dependsOn(variantScope.getAssembleTask()); } if (variantConfig.getProductFlavors().size() > 1) { final String name = StringHelper.capitalize(variantConfig.getFlavorName()); final String variantAssembleTaskName = StringHelper.appendCapitalized("assemble", name); if (!taskManager.getTaskFactory().containsKey(variantAssembleTaskName)) { Task task = taskManager.getTaskFactory().create(variantAssembleTaskName); task.setDescription("Assembles all builds for flavor combination: " + name); task.setGroup("Build"); task.dependsOn(variantScope.getAssembleTask().getName()); } taskManager .getTaskFactory() .configure( "assemble", task1 -> task1.dependsOn(variantAssembleTaskName)); } } } }
|
上面会生成包括 BuildType、Flavor、BuildType + Flavor + VariantType 的 assemble task,同时 task 之间存在依赖关系:assemble > buildType/flavor > 具体
除了上面所说的 assemble task,还将生成以下 task:
task |
impl |
dependsOn |
assemble{variant} |
DefaultTask |
compile{variant}Sources,package{variant} |
pre{variant}Build |
AppPreBuildTask |
preBuild,extractProguardFiles(可能) |
extractProguardFiles |
ExtractProguardFiles |
|
generate{variant}Sources |
DefaultTask |
compile{variant}Renderscript,generate{variant}BuildConfig,bundle{variant}Resources,compile{variant}Aidl |
generate{variant}Resources |
DefaultTask |
generate{variant}ResValues,compile{variant}Renderscript |
generate{variant}Assets |
DefaultTask |
compile{variant}Shaders |
compile{variant}Sources |
DefaultTask |
compile{variant}Ndk,compile{variant}JavaWithJavac |
check{variant}Manifest |
CheckManifest |
pre{variant}Build |
write{variant}ApplicationId |
ApplicationIdIdWriteTask |
|
mainApkListPersistence{variant} |
MainApkListPersistence |
|
reportBuildArtifacts{variant} |
BuildArtifactReportTask |
|
create{variant}CompatibleScreenManifests |
CompatibleScreensManifest |
|
process{variant}Manifest |
MergeManifests |
check{variant}Manifest |
generate{variant}ResValues |
GenerateResValues |
|
compile{variant}Renderscript |
RenderscriptCompile |
pre{variant}Build |
merge{variant}Resources |
MergeResources |
generate{variant}Resources |
merge{variant}Shaders |
MergeSourceSetFolders |
|
compile{variant}Shaders |
ShaderCompile |
merge{variant}Shaders |
merge{variant}Assets |
MergeSourceSetFolders |
generate{variant}Assets |
generate{variant}BuildConfig |
GenerateBuildConfig |
check{variant}Manifest |
splitsDiscoveryTask{variant} |
SplitsDiscovery |
|
process{variant}JavaRes |
Sync |
pre{variant}Build |
process{variant}Resources |
LinkApplicationAndroidResourcesTask |
|
bundle{variant}Resources |
LinkAndroidResForBundleTask |
|
compile{variant}Aidl |
AidlCompile |
pre{variant}Build |
compile{variant}Ndk |
NdkCompile |
pre{variant}Build |
merge{variant}JniLibFolders |
MergeSourceSetFolders |
generate{variant}Assets |
javaPreCompile{variant} |
JavaPreCompileTask |
pre{variant}Build |
compile{variant}JavaWithJavac |
AndroidJavaCompile |
generate{variant}Sources |
bundleAppClasses{variant} |
Jar |
|
transformResourcesWithMergeJavaResFor{variant} |
TransformTask |
|
transformClassesWithMultidexlistFor{variant} |
TransformTask |
|
transformClassesWithDexBuilderFor{variant} |
TransformTask |
|
transformDexArchiveWithDexMergerFor{variant} |
TransformTask |
transformClassesWithMultidexlistFor{variant} |
preparePUBLISHED_JAVA_RES{variant}ForPublishing |
PipelineToPublicationTask |
|
package{variant} |
PackageApplication |
merge{variant}Assets,process{variant}Resources,validateSigning{variant},compile{variant}JavaWithJavac |
validateSigning{variant} |
ValidateSigningTask |
|
install{variant} |
InstallVariantTask |
assemble{variant} |
uninstall{variant} |
UninstallTask |
|
lint{variant} |
LintPerVariantTask |
|
以 assembleProdRelease
命令,依次执行的 task:
prod 是 product flavor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| preBuild extractProguardFiles preProdReleaseBuild compileProdReleaseRenderscript checkProdReleaseManifest generateProdReleaseBuildConfig prepareLintJar mainApkListPersistenceProdRelease generateProdReleaseResValues generateProdReleaseResources compileProdReleaseAidl createProdReleaseCompatibleScreenManifests processProdReleaseManifest mergeProdReleaseResources // 合并资源 splitsDiscoveryTaskProdRelease processProdReleaseResources generateProdReleaseSources javaPreCompileProdRelease compileProdReleaseJavaWithJavac // javac compileProdReleaseNdk compileProdReleaseSources mergeProdReleaseShaders compileProdReleaseShaders generateProdReleaseAssets mergeProdReleaseAssets transformClassesWithComponentCodeForProdRelease processProdReleaseJavaRes transformResourcesWithMergeJavaResForProdRelease transformClassesAndResourcesWithProguardForProdRelease // 混淆 transformClassesWithMultidexlistForProdRelease transformClassesWithDexForProdRelease // dex transformClassesWithShrinkResForProdRelease mergeProdReleaseJniLibFolders transformNativeLibsWithMergeJniLibsForProdRelease validateSigningProdRelease packageProdRelease
|
接下来分析下比较重要的几个 task
接下来的分析,因为对应的源码比较复杂,所以只会简短介绍结果,没有详细过程,推荐 debug 整个流程
CompileJavaWithJavac
首先找到执行的 AndroidJavaCompile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Override protected void compile(IncrementalTaskInputs inputs) { if (isPostN()) { if (!JavaVersion.current().isJava8Compatible()) { throw new RuntimeException("compileSdkVersion '" + compileSdkVersion + "' requires " + "JDK 1.8 or later to compile."); } } processAnalytics(); FileUtils.mkdirs(annotationProcessorOutputFolder); mInstantRunBuildContext.startRecording(InstantRunBuildContext.TaskType.JAVAC); super.compile(inputs); mInstantRunBuildContext.stopRecording(InstantRunBuildContext.TaskType.JAVAC); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @TaskAction protected void compile(IncrementalTaskInputs inputs) { if (!this.compileOptions.isIncremental()) { this.compile(); } else { DefaultJavaCompileSpec spec = this.createSpec(); CompileCaches compileCaches = this.createCompileCaches(); IncrementalCompilerFactory factory = new IncrementalCompilerFactory(this.getFileOperations(), this.getStreamHasher(), this.getCachingFileHasher(), this.getPath(), this.createCompiler(spec), this.source, compileCaches, (IncrementalTaskInputsInternal)inputs, this.getEffectiveAnnotationProcessorPath()); Compiler<JavaCompileSpec> compiler = factory.createCompiler(); this.performCompilation(spec, compiler); } }
|
不管是增量编译还是全量编译,最后都会调用 performCompilation
1 2 3 4 5
| private void performCompilation(JavaCompileSpec spec, Compiler<JavaCompileSpec> compiler) { WorkResult result = compiler.execute(spec); this.setDidWork(result.getDidWork()); }
|
Compiler 采用装饰者设计模式,最外层是 CleaningJavaCompilerSupport
会先删除编译目录,再调用 JdkJavaCompiler
执行 javac
过程,具体为,创建一个 JavacTaskImpl
然后 JavacTask 会调用 com.sun.tools.javac.main.Main
进行处理,其中创建 JavacTask 的任务是由 JavacTool
完成