parent
							
								
									5e70f61e8d
								
							
						
					
					
						commit
						596be60c7b
					
				| @ -0,0 +1,273 @@ | ||||
| --- | ||||
| Android Plugin 主要 Task 分析 | ||||
| --- | ||||
| 
 | ||||
| > 本文摘自:[Android Gradle Plugin 主要 Task 分析](https://github.com/5A59/android-training/blob/master/gradle/android_gradle_plugin-%E4%B8%BB%E8%A6%81task%E5%88%86%E6%9E%90.md) | ||||
| > | ||||
| > 感谢美团大佬 [@5A59](https://github.com/5A59) 的分享! | ||||
| 
 | ||||
| ### 目录 | ||||
| 
 | ||||
| 1. 打包流程 | ||||
| 2. Task 对应实现类 | ||||
| 3. 如何去读 Task 的代码 | ||||
| 
 | ||||
| ### 打包流程 | ||||
| 
 | ||||
| 这次,我们以 Task 的维度来看 APK 的打包流程。在项目的根目录执行以下命令: | ||||
| 
 | ||||
| ``` | ||||
| ./gradlew :app:assembleDebug --console=plain | ||||
| ``` | ||||
| 
 | ||||
| 输出结果为: | ||||
| 
 | ||||
| ``` | ||||
| > Task :app:preBuild UP-TO-DATE | ||||
| > Task :app:preDebugBuild UP-TO-DATE | ||||
| > Task :app:compileDebugAidl NO-SOURCE | ||||
| > Task :app:compileDebugRenderscript NO-SOURCE | ||||
| > Task :app:checkDebugManifest UP-TO-DATE | ||||
| > Task :app:generateDebugBuildConfig UP-TO-DATE | ||||
| > Task :app:prepareLintJar UP-TO-DATE | ||||
| > Task :app:generateDebugSources UP-TO-DATE | ||||
| > Task :app:javaPreCompileDebug UP-TO-DATE | ||||
| > Task :app:mainApkListPersistenceDebug UP-TO-DATE | ||||
| > Task :app:generateDebugResValues UP-TO-DATE | ||||
| > Task :app:generateDebugResources UP-TO-DATE | ||||
| > Task :app:mergeDebugResources UP-TO-DATE | ||||
| > Task :app:createDebugCompatibleScreenManifests UP-TO-DATE | ||||
| > Task :app:processDebugManifest UP-TO-DATE | ||||
| > Task :app:processDebugResources UP-TO-DATE | ||||
| > Task :app:compileDebugJavaWithJavac UP-TO-DATE | ||||
| > Task :app:compileDebugSources UP-TO-DATE | ||||
| > Task :app:mergeDebugShaders UP-TO-DATE | ||||
| > Task :app:compileDebugShaders UP-TO-DATE | ||||
| > Task :app:generateDebugAssets UP-TO-DATE | ||||
| > Task :app:mergeDebugAssets UP-TO-DATE | ||||
| > Task :app:checkDebugDuplicateClasses UP-TO-DATE | ||||
| > Task :app:mergeExtDexDebug UP-TO-DATE | ||||
| > Task :app:mergeLibDexDebug UP-TO-DATE | ||||
| > Task :app:transformClassesWithDexBuilderForDebug UP-TO-DATE | ||||
| > Task :app:mergeProjectDexDebug UP-TO-DATE | ||||
| > Task :app:validateSigningDebug UP-TO-DATE | ||||
| > Task :app:signingConfigWriterDebug UP-TO-DATE | ||||
| > Task :app:mergeDebugJniLibFolders UP-TO-DATE | ||||
| > Task :app:transformNativeLibsWithMergeJniLibsForDebug UP-TO-DATE | ||||
| > Task :app:processDebugJavaRes NO-SOURCE | ||||
| > Task :app:transformResourcesWithMergeJavaResForDebug UP-TO-DATE | ||||
| > Task :app:packageDebug UP-TO-DATE | ||||
| > Task :app:assembleDebug UP-TO-DATE | ||||
| ``` | ||||
| 
 | ||||
| 上面就是打包一个 APK 需要的 Task。 | ||||
| 
 | ||||
| ### Task 对应实现类 | ||||
| 
 | ||||
| 我们先看看每个 task 都是做什么的,以及其对应的实现类。 | ||||
| 
 | ||||
| 先回忆一下,我们在前面分析 Android Plugin 主要流程时说过,task 的实现可以在 TaskManager 里找到,创建 Task 的方法主要是两个,TaskManager.createTasksBeforeEvaluate() 和 ApplicationTaskManager.createTasksForVariantScope(),所有这些 Task 的实现,也是在这两个类就可以找到,下面列出了各个 Task 的作用及实现类。 | ||||
| 
 | ||||
| | Task                                                 | 对应实现类                  | 作用                                                         | | ||||
| | ---------------------------------------------------- | --------------------------- | ------------------------------------------------------------ | | ||||
| | preBuild                                             |                             | 空 Task,只做锚点使用                                        | | ||||
| | preDebugBuild                                        |                             | 空 Task,只做锚点使用,与 preBuild 区别是这个 task 是 variant 的锚点 | | ||||
| | compileDebugAidl                                     | AidlCompile                 | 处理 aidl                                                    | | ||||
| | compileDebugRenderscript                             | RendersciptCompiler         | 处理 renderscript                                            | | ||||
| | checkDebugManifest                                   | CheckManifest               | 检查 manifest 是否存在                                       | | ||||
| | generateDebugBuildConfig                             | GenerateBuildConfig         | 生成 BuildConfig.java                                        | | ||||
| | prepareLintJar                                       | PrepareLintJar              | 拷贝 lint jar 包到指定位置                                   | | ||||
| | generateDebugResValues                               | GenerateResValues           | 生成 res values generated.xml                                | | ||||
| | generateDebugResources                               |                             | 空 Task,锚点                                                | | ||||
| | mergeDebugResources                                  | MergeResources              | 合并资源文件                                                 | | ||||
| | createDebugCompatibleScreenManifest                  | CompatibleScreensManifest   | manifest 文件中生成 compatible-screens,指定屏幕适配         | | ||||
| | processDebugManifest                                 | MergeManifests              | 合并 manifest 文件                                           | | ||||
| | splitsDiscoveryTaskDebug                             | SplitsDiscovery             | 生成 split-list.json,用于 apk 分包                          | | ||||
| | processDebugResources                                | ProcessAndroidResources     | aapt 打包资源                                                | | ||||
| | generateDebugSources                                 |                             | 空 Task,锚点                                                | | ||||
| | javaPreCompileDebug                                  | JavaPreCompileTask          | 生成 annotationProcessors.json 文件                          | | ||||
| | compileDebugJavaWithJavac                            | AndroidJavaCompile          | 编译 java 文件                                               | | ||||
| | compileDebugNdk                                      | NdkCompile                  | 编译 ndk                                                     | | ||||
| | compileDebugSources                                  |                             | 空 Task,锚点                                                | | ||||
| | mergeDebugShaders                                    | MergeSourceSetFolders       | 合并 shader文件                                              | | ||||
| | compileDebugShaders                                  | ShaderCompile               | 编译 shaders                                                 | | ||||
| | generateDebugAssets                                  |                             | 空 Task,锚点                                                | | ||||
| | mergeDebugAssets                                     | MergeSourceSetFolders       | 合并 assets 文件                                             | | ||||
| | transformClassesWithDexBuilderForDebug               | DexArchiveBuilderTransform  | class 打包 dex                                               | | ||||
| | transformDexArchiveWithExternalLibsDexMergerForDebug | ExternalLibsMergerTransform | 打包第三方库的 dex,在 dex 增量的时候就不需要再 merge 了,节省时间 | | ||||
| | transformDexArchiveWithDexMergerForDebug             | DexMergerTransform          | 打包最终的 dex                                               | | ||||
| | mergeDebugJniLibFolders                              | MergeSouceSetFolders        | 合并 jni lib 文件                                            | | ||||
| | transformNativeLibsWithMergeJniLibsForDebug          | MergeJavaResourcesTransform | 合并 jnilibs                                                 | | ||||
| | transformNativeLibsWithStripDebugSymbolForDebug      | StripDebugSymbolTransform   | 去掉 native lib 里的 debug 符号                              | | ||||
| | processDebugJavaRes                                  | ProcessJavaResConfigAction  | 处理 java res                                                | | ||||
| | transformResourcesWithMergeJavaResForDebug           | MergeJavaResourcesTransform | 合并 java res                                                | | ||||
| | validateSigningDebug                                 | ValidateSigningTask         | 验证签名                                                     | | ||||
| | packageDebug                                         | PackageApplication          | 打包 apk                                                     | | ||||
| | assembleDebug                                        |                             | 空 Task,锚点                                                | | ||||
| 
 | ||||
| ### 如何去读 Task 的代码 | ||||
| 
 | ||||
| 在 Gradle Plugin 中的 Task 主要有三种,一种是普通的 task,一种是增量的 task,一种是 transform,下面分别看下这三种 task 怎么去读。 | ||||
| 
 | ||||
| 如何去读? | ||||
| 
 | ||||
| 1. 看 Task 继承的父类,一般来说,会继承 DefaultTask、IncrementalTask | ||||
| 2. 看 @TaskAction 注解的方法,此方法就是这个 Task 做的事情 | ||||
| 
 | ||||
| 如何读 IncrementalTask? | ||||
| 
 | ||||
| 我们先看看这个类,这个类表示的是增量 Task,什么是增量呢?是相对于全量来说的,全量我们可以理解为调用 clean 以后第一次编译的过程,这个就是全量编译,之后修改了代码或者资源文件,再次编译,就是增量编译。 | ||||
| 
 | ||||
| 其中比较重要的有以下几个方法: | ||||
| 
 | ||||
| ```java | ||||
| public abstract class IncrementalTask extends BaseTask { | ||||
|     // ... | ||||
|     @Internal | ||||
|     protected boolean isIncremental() {  | ||||
|         // 是否需要增量,默认是 false | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // 需要子类实现,全量的时候执行的任务 | ||||
|     protected abstract void doFullTaskAction() throws Exception; | ||||
| 
 | ||||
|     // 增量的时候执行的任务,默认是什么都不执行,参数是增量的时候修改过的文件 | ||||
|     protected void doIncrementalTaskAction(Map<File, FileStatus> changedInputs) throws Exception { | ||||
|     } | ||||
| 
 | ||||
|     @TaskAction | ||||
|     void taskAction(IncrementalTaskInputs inputs) throws Exception { | ||||
|         // 判断是否是增量 | ||||
|         if(this.isIncremental() && inputs.isIncremental()) {  | ||||
|             this.doIncrementalTaskAction(this.getChangedInputs(inputs)); | ||||
|         } else { | ||||
|             this.getProject().getLogger().info("Unable do incremental execution: full task run"); | ||||
|             this.doFullTaskAction(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 获取修改的文件 | ||||
|     private Map<File, FileStatus> getChangedInputs(IncrementalTaskInputs inputs) { | ||||
|         Map<File, FileStatus> changedInputs = Maps.newHashMap(); | ||||
|         inputs.outOfDate((change) -> { | ||||
|             FileStatus status = change.isAdded()?FileStatus.NEW:FileStatus.CHANGED; | ||||
|             changedInputs.put(change.getFile(), status); | ||||
|         }); | ||||
|         inputs.removed((change) -> { | ||||
|             FileStatus var10000 = (FileStatus)changedInputs.put(change.getFile(), FileStatus.REMOVED); | ||||
|         }); | ||||
|         return changedInputs; | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 简单介绍了 IncrementalTask 之后,我们这里强调一下,如何去读一个增量 Task 的代码,主要有四步: | ||||
| 
 | ||||
| 1. 首先这个 Task 要继承 IncrementalTask | ||||
| 2. 其次看 isIncremental 方法,如果返回 true,说明支持增量,返回 false 则不支持 | ||||
| 3. 然后看 doFullTaskAction 方法,是全量的时候执行的操作 | ||||
| 4. 最后看 doIncrementalTaskAction 方法,这里是增量的时候执行的操作 | ||||
| 
 | ||||
| 如何读 Transform? | ||||
| 
 | ||||
| 1. 继承自 Transfrom | ||||
| 2. 看其 transform 方法的实现 | ||||
| 
 | ||||
| ### 重点 Task 实现分析 | ||||
| 
 | ||||
| 上面每个 task 已经简单说明了具体做什么以及对应的实现类,下面选了几个比较重要的来分析一下其实现。为什么分析这几个呢?这几个代表了 gradle 自动生成代码、资源的处理,以及 dex 的处理,算是 apk 打包过程中比较重要的几环。 | ||||
| 
 | ||||
| generateDebugBuildConfig | ||||
| 
 | ||||
| processDebugManifest | ||||
| 
 | ||||
| mergeDebugResources | ||||
| 
 | ||||
| processDebugResources | ||||
| 
 | ||||
| transformClassesWithDexBuilderForDebug | ||||
| 
 | ||||
| transformDexArchiveWithExternalLibsDexMergerForDebug | ||||
| 
 | ||||
| transformDexArchivesWithDexMergerForDebug | ||||
| 
 | ||||
| 分析过程主要下面几个步骤,整体实现图、调用链路以及重要代码分析。 | ||||
| 
 | ||||
| #### generateDebugBuildConfig | ||||
| 
 | ||||
| 实现类: | ||||
| 
 | ||||
| GenerateBuildConfig。 | ||||
| 
 | ||||
| 整体实现图: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 代码调用链路: | ||||
| 
 | ||||
| ``` | ||||
| GenerateBuildConfig.generate -> BuildConfigGenerator.generate -> JavaWriter | ||||
| ``` | ||||
| 
 | ||||
| 主要代码分析: | ||||
| 
 | ||||
| 在 GenerateBuildConfig 中,主要生成代码的步骤如下: | ||||
| 
 | ||||
| 1. 生成 BuildConfigGenerator | ||||
| 2. 添加默认的属性,包括 DEBUG、APPLICATION_ID、FLAVOR、VERSION_CODE、VERSION_NAME | ||||
| 3. 添加自定义属性 | ||||
| 4. 调用 JavaWrite 生成 BuildConfig.java 文件 | ||||
| 
 | ||||
| ```java | ||||
| // GenerateBuildConfig.generate()   | ||||
| @TaskAction | ||||
| void generate() throws IOException { | ||||
|     // ... | ||||
|     BuildConfigGenerator generator = new BuildConfigGenerator( | ||||
|             getSourceOutputDir(), | ||||
|             getBuildConfigPackageName()); | ||||
|     // 添加默认的属性,包括 DEBUG,APPLICATION_ID,FLAVOR,VERSION_CODE,VERSION_NAME | ||||
|     generator | ||||
|             .addField( | ||||
|                     "boolean", | ||||
|                     "DEBUG", | ||||
|                     isDebuggable() ? "Boolean.parseBoolean(\"true\")" : "false") | ||||
|             .addField("String", "APPLICATION_ID", '"' + appPackageName.get() + '"') | ||||
|             .addField("String", "BUILD_TYPE", '"' + getBuildTypeName() + '"') | ||||
|             .addField("String", "FLAVOR", '"' + getFlavorName() + '"') | ||||
|             .addField("int", "VERSION_CODE", Integer.toString(getVersionCode())) | ||||
|             .addField( | ||||
|                     "String", "VERSION_NAME", '"' + Strings.nullToEmpty(getVersionName()) + '"') | ||||
|             .addItems(getItems()); // 添加自定义属性 | ||||
| 
 | ||||
|     List<String> flavors = getFlavorNamesWithDimensionNames(); | ||||
|     int count = flavors.size(); | ||||
|     if (count > 1) { | ||||
|         for (int i = 0; i < count; i += 2) { | ||||
|             generator.addField( | ||||
|                     "String", "FLAVOR_" + flavors.get(i + 1), '"' + flavors.get(i) + '"'); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 内部调用 JavaWriter 生成 java 文件 | ||||
|     generator.generate(); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| #### mergeDebugResources | ||||
| 
 | ||||
| 实现类: | ||||
| 
 | ||||
| MergeResources | ||||
| 
 | ||||
| 整体实现图: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 调用链路: | ||||
| 
 | ||||
| ``` | ||||
| MergeResources.doFullTaskAction -> ResourceMerger.mergeData -> MergedResourceWriter.end -> QueueableAapt2.compile ->  | ||||
| ``` | ||||
| 
 | ||||
| After Width: | Height: | Size: 70 KiB | 
| After Width: | Height: | Size: 124 KiB | 
					Loading…
					
					
				
		Reference in new issue