文章目录

  • Task29 checkDebugLibraries
    • 1. inut/ouput
    • 2. 核心类(CheckMultiApkLibrariesTask)
  • Task30 processDebugJavaRes
    • 1. 预操作
    • 1. input/ouput
    • 核心类(ProcessJavaResConfigAction, SYNC)
  • Task31 transformResourcesWithMergeJavaResForDebug
    • 1. input/ouput
    • 2. 核心类(MergeJavaResourcesTransform)
  • Task32 validateSigningDebug
    • 核心类(ValidateSigningTask)
  • Task 33 packageDebug
    • 1. input/ouput
    • 2. 核心类(PackageApplication)

Task29 checkDebugLibraries

1. inut/ouput

taskName:checkDebugLibraries
=========================================================
output:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/check-libraries/debug

这个任务就是用来做校验的,如果存在多个modules打包成相同库,则会提示报错

2. 核心类(CheckMultiApkLibrariesTask)

@TaskAction
fun taskAction() {// Build a map of libraries to their corresponding modules. If two modules package the same// library, we will use the map to output a user-friendly error message.val map = mutableMapOf<String, MutableList<String>>()var found = falsefor (artifact in featureTransitiveDeps) {// Sanity check. This should never happen.if (artifact.id.componentIdentifier !is ProjectComponentIdentifier) {throw GradleException(artifact.id.componentIdentifier.displayName + " is not a Gradle project.")}val projectPath =(artifact.id.componentIdentifier as ProjectComponentIdentifier).projectPathif (artifact.file.isFile) {found = found || updateLibraryMap(artifact.file, projectPath, map)}}if (found) {// Build the error message. Sort map and projectPaths for consistency.val output = StringBuilder()for ((library, projectPaths) in map.toSortedMap()) {if (projectPaths.size > 1) {output.append(projectPaths.sorted().joinToString(prefix = "[", postfix = "]")).append(" all package the same library [$library].\n")}}throw GradleException(output.toString())}}private fun updateLibraryMap(file: File,projectPath: String,map: MutableMap<String, MutableList<String>>
): Boolean {var found = falsefor (library in Files.readLines(file, Charsets.UTF_8)) {val libraryWithoutVariant = library.substringBeforeLast("::")if (map.containsKey(libraryWithoutVariant)) {found = truemap[libraryWithoutVariant]?.add(projectPath)} else {map[libraryWithoutVariant] = mutableListOf(projectPath)}}return found
}

Task30 processDebugJavaRes

1. 预操作

在debug/main目录新增resources添加文件

1. input/ouput

taskName:processDebugJavaRes
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/src/main/resources/main-resources.txt
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/src/debug/resources/debug-resources.txt
=========================================================
output:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/sourceFolderJavaResources/debug

可以看到该任务就是将app中的resources中文件copy而已

核心类(ProcessJavaResConfigAction, SYNC)

// ProcessJavaResConfigAction.java
public void execute(@NonNull Sync processResources) {// 执行预操作for (SourceProvider sourceProvider :scope.getVariantConfiguration().getSortedSourceProviders()) {processResources.from(((AndroidSourceSet) sourceProvider).getResources().getSourceFiles());}processResources.setDestinationDir(destinationDir);}

复制操作其实是交给SYNC这个类处理的,也就是sync任务,可以理解为是一个copy操作,只是可以通过preserve来指定目标目录那些可以删除,那些可以保留
具体参考官方文档https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Sync.html

Task31 transformResourcesWithMergeJavaResForDebug

1. input/ouput

taskName:transformResourcesWithMergeJavaResForDebug
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/libs/java-json.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/adapters-3.2.0.aar/bc960c7c2fdbe5a1b97481ebd16e7d07/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/library-3.2.0.aar/de8b548685f788612cb022c06f944e21/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/modules-2/files-2.1/com.android.databinding/baseLibrary/3.2.0/fb5f8492c36231104cd86feaefa723291504c0a6/baseLibrary-3.2.0.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/multidex-1.0.2.aar/bf674b553893d1ca7ec3045705c93ed8/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/3835acebdd7fa231db259f7088788607/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/dafb9764e639c30db91be97006e47787/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/support-v4-26.1.0.aar/e50a7ebe45a7183db73f76387f58eadf/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/support-fragment-26.1.0.aar/68eceb6dacbf0dc308d62e2a91559369/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/support-core-utils-26.1.0.aar/137dca77f851b0e904bb098c1da042aa/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-26.1.0.aar/c49cb8624209768bd4984b8fead22f48/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-26.1.0.aar/4a854f4c19aeb19de51777bbccdc7f48/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/6c38555fbd7f9d3e1a9de701d85ad85e/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/support-core-ui-26.1.0.aar/445504c8690be77ae0900482a270f4e9/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/160cc69dee260ec7a028fa1574fd87ba/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/transforms-1/files-1.1/runtime-1.0.3.aar/b7c442e59ee627256a254a2a31de63ac/jars/classes.jar
input:/Users/dingbaosheng/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.0.3/7d7f60c4783872861222166f6164215f8951c7b1/common-1.0.3.jar
input:/Users/dingbaosheng/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.0.0/a2d487452376193fc8c103dd2b9bd5f2b1b44563/common-1.0.0.jar
input:/Users/dingbaosheng/.gradle/caches/modules-2/files-2.1/com.android.support/support-annotations/26.1.0/814258103cf26a15fcc26ecce35f5b7d24b73f8/support-annotations-26.1.0.jar
input:/Users/dingbaosheng/.gradle/caches/modules-2/files-2.1/com.android.support.constraint/constraint-layout-solver/1.1.3/bde0667d7414c16ed62d3cfe993cff7f9d732373/constraint-layout-solver-1.1.3.jar
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/sourceFolderJavaResources/debug/debug-resources.txt
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/sourceFolderJavaResources/debug/main-resources.txt
=========================================================
output:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/incremental/debug-mergeJavaRes/zip-cache
output:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/transforms/mergeJavaRes/debug

这个任务就是合并java资源文件(注意:此处资源文件不是指layout,asset,dex等资源文件)而是指标准等Java资源

看下mergeJavaRes/debug/0.jar产物,解压如下

可以看到文件如下

  • META-INF记录了App中注解处理器涉及的各库版本
  • 我们在resources目录添加的资源文件
  • 如果jar中包含.java文件也会被包含打包

2. 核心类(MergeJavaResourcesTransform)

核心类和task28一样,此处略过

Task32 validateSigningDebug

该任务就是用来验证deubug模式下keystore文件是否存在,如果不存在直接创建并保存,
因为我们Sample工程并没有配置sign属性,所以打包默认会使用debug-keystore进行签名

核心类(ValidateSigningTask)

/*** A Gradle Task to check that the keystore file is present for this variant's signing config.** If the keystore is the default debug keystore, it will be created if it is missing.** This task has no explicit inputs, but is forced to run if the signing config keystore file is* not present.*/
open class ValidateSigningTask : AndroidVariantTask() {/*** Output directory to allow this task to be up-to-date, despite the the signing config file* not being modelled directly as an input or an output.*/@get:OutputDirectory lateinit var dummyOutputDirectory: Fileprivate setprivate lateinit var signingConfig: SigningConfigprivate lateinit var defaultDebugKeystoreLocation: File@TaskAction@Throws(ExecutionException::class, IOException::class)fun validate() = when {signingConfig.storeFile == null -> throw InvalidUserDataException("""Keystore file not set for signing config ${signingConfig.name}""")isSigningConfigUsingTheDefaultDebugKeystore() ->/* Check if the debug keystore is being used rather than directly checking if italready exists. A "fast path" of returning true if the store file is present wouldallow one task to return while another validate task has only partially written thedefault debug keystore file, which could lead to confusing transient build errors. */createDefaultDebugKeystoreIfNeeded()signingConfig.storeFile?.isFile == true -> {/* Keystore file is present, allow the build to continue. */}else -> throw InvalidUserDataException("""Keystore file '${signingConfig.storeFile?.absolutePath}' """+ """not found for signing config '${signingConfig.name}'.""")}// 如果/Users/{USER_NAME}/.android/debug.keystore不存在,创建一个debug.keystore@Throws(ExecutionException::class, IOException::class)private fun createDefaultDebugKeystoreIfNeeded() {checkState(signingConfig.isSigningReady, "Debug signing config not ready.")if (!defaultDebugKeystoreLocation.parentFile.canWrite()) {throw IOException("""Unable to create debug keystore in """+ """${defaultDebugKeystoreLocation.parentFile.absolutePath} because it is not writable.""")}/* Synchronized file with multi process locking requires that the parent directory of thedefault debug keystore is present.It is created as part of KeystoreHelper.defaultDebugKeystoreLocation() */checkState(FileUtils.parentDirExists(defaultDebugKeystoreLocation),"Parent directory of the default debug keystore '%s' does not exist",defaultDebugKeystoreLocation)/* Creating the debug keystore is done with the multi process file locking,to avoid one validate signing task from exiting early while the keystore is in theprocess of being written.The keystore is not locked in the task input presence check or where it is used atapplication packaging.This is generally safe as the keystore is only automatically created,never automatically deleted.  */SynchronizedFile.getInstanceWithMultiProcessLocking(defaultDebugKeystoreLocation).createIfAbsent { createDefaultDebugStore(it, this.logger) }}private fun isSigningConfigUsingTheDefaultDebugKeystore(): Boolean {return signingConfig.name == BuilderConstants.DEBUG &&signingConfig.keyAlias == DefaultSigningConfig.DEFAULT_ALIAS &&signingConfig.keyPassword == DefaultSigningConfig.DEFAULT_PASSWORD &&signingConfig.storePassword == DefaultSigningConfig.DEFAULT_PASSWORD &&signingConfig.storeType == KeyStore.getDefaultType() &&signingConfig.storeFile.isSameFile(defaultDebugKeystoreLocation)}...
}

Task 33 packageDebug

1. input/ouput

taskName:packageDebug
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/apk_list/debug/mainApkListPersistenceDebug/apk-list.gson
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/merged_assets/debug/mergeDebugAssets/out
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/transforms/dexMerger/debug/0
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/transforms/mergeJavaRes/debug/0.jar
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/merged_manifests/debug/processDebugManifest/merged
input:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/processed_res/debug/processDebugResources/out
input:/Users/dingbaosheng/.android/debug.keystore
=========================================================
output:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/intermediates/incremental/packageDebug/tmp
output:/Users/dingbaosheng/work/mockuai/project/AndroidGradleTaskDemo/app/build/outputs/apk/debug

这个任务就是打包任务,把之前的任务产物作为输入打包成一个apk,主要流程图如下

2. 核心类(PackageApplication)

/** Task to package an Android application (APK). */
public class PackageApplication extends PackageAndroidArtifact {}

可以看到PackageApplication继承类PackageAndroidArtifact,任务入口集中在基类

//PackageAndroidArtifact.java
@Override
protected void doFullTaskAction() {// check that we don't have colliding output file namescheckFileNameUniqueness();ExistingBuildElements.from(getTaskInputType(), resourceFiles).transform((ApkInfo apkInfo, File inputFile) -> {try {return splitFullAction(apkInfo, inputFile);} catch (IOException e) {throw new BuildException(e.getMessage(), e);}}).into(getInternalArtifactType(), outputDirectory);}

可以看到方法最终调用splitFullAction方法

public File splitFullAction(@NonNull ApkInfo apkData, @Nullable File processedResources)throws IOException {File incrementalDirForSplit = new File(getIncrementalFolder(), apkData.getFullName());/** Clear the intermediate build directory. We don't know if anything is in there and* since this is a full build, we don't want to get any interference from previous state.*/if (incrementalDirForSplit.exists()) {FileUtils.deleteDirectoryContents(incrementalDirForSplit);} else {FileUtils.mkdirs(incrementalDirForSplit);}File cacheByPathDir = new File(incrementalDirForSplit, ZIP_DIFF_CACHE_DIR);FileUtils.mkdirs(cacheByPathDir);FileCacheByPath cacheByPath = new FileCacheByPath(cacheByPathDir);/** Clear the cache to make sure we have do not do an incremental build.*/cacheByPath.clear();Set<File> androidResources = getAndroidResources(processedResources);FileUtils.mkdirs(outputDirectory);BuildOutput buildOutput = computeBuildOutputFile(apkData);File outputFile = buildOutput.getOutputFile();/** Additionally, make sure we have no previous package, if it exists.*/FileUtils.deleteIfExists(outputFile);final ImmutableMap<RelativeFile, FileStatus> updatedDex;final ImmutableMap<RelativeFile, FileStatus> updatedJavaResources;if (!hasFeatureDexFiles()) {// 1. 读取dex文件(合并后的)updatedDex = IncrementalRelativeFileSets.fromZipsAndDirectories(getDexFolders());// 2. 加载标准java资源文件(eg:0.jar)updatedJavaResources = getJavaResourcesChanges();} else {// We reach this code if we're in a feature module and minification is enabled in the// base module. In this case, we want to use the classes.dex file from the base// module's DexSplitterTransform.checkNotNull(getFeatureDexFolder());updatedDex = IncrementalRelativeFileSets.fromZipsAndDirectories(getFeatureDexFolder());// For now, java resources are in the base apk, so we exclude them here (b/77546738)updatedJavaResources = ImmutableMap.of();}// 3. 加载merged后的assets文件ImmutableMap<RelativeFile, FileStatus> updatedAssets =IncrementalRelativeFileSets.fromZipsAndDirectories(assets.getFiles());// 4. 加载android资源库文件(eg:resources-debug*.ap_)ImmutableMap<RelativeFile, FileStatus> updatedAndroidResources =IncrementalRelativeFileSets.fromZipsAndDirectories(androidResources);// 5. so相关文件ImmutableMap<RelativeFile, FileStatus> updatedJniResources =IncrementalRelativeFileSets.fromZipsAndDirectories(getJniFolders());// 6. 清合后的清单文件BuildElements manifestOutputs = ExistingBuildElements.from(manifestType, manifests);// 7. 打包成apk,最终是通过一个叫ApkZFileCreator类进行打包的doTask(apkData,incrementalDirForSplit,outputFile,cacheByPath,manifestOutputs,updatedDex,updatedJavaResources,updatedAssets,updatedAndroidResources,updatedJniResources);/** Update the known files.*/KnownFilesSaveData saveData = KnownFilesSaveData.make(incrementalDirForSplit);saveData.setInputSet(updatedDex.keySet(), InputSet.DEX);saveData.setInputSet(updatedJavaResources.keySet(), InputSet.JAVA_RESOURCE);saveData.setInputSet(updatedAssets.keySet(), InputSet.ASSET);saveData.setInputSet(updatedAndroidResources.keySet(), InputSet.ANDROID_RESOURCE);saveData.setInputSet(updatedJniResources.keySet(), InputSet.NATIVE_RESOURCE);saveData.saveCurrentData();recordMetrics(outputFile, processedResources);return outputFile;
}

Android构建流程——篇八相关推荐

  1. Android构建流程——篇二

    文章目录 预操作 任务列表 如何查看一个task类 Task1: checkDebugClasspath 1. input/output 2. 如何找到任务实现类 3. 核心类(AppClasspat ...

  2. Android构建流程——篇一

    Android构建流程 前言 APK 构建流程 AGP(3.2.0)任务列表总览图 参考文献 前言 大家平时开发Android项目时一般都是点击AS run按钮,这样apk会自动安装到手机上,这整个过 ...

  3. Android构建流程——篇七

    文章目录 Task24 transformClassesWithDexBuilderForDebug 1.input/ouput 2. 核心类(DexArchiveBuilderTransform,T ...

  4. Android构建流程——篇四

    文章目录 Task9 generateDebugResValues 1. input/ouput 2. 核心类(GenerateResValues) Task10 generateDebugResou ...

  5. Android构建流程——篇六

    文章目录 Task17: javaPreCompileDebug 1. input/ouput 2. 验证 3. 核心类(JavaPreCompileTask) Task18:compileDebug ...

  6. Android构建流程——篇五

    文章目录 Task13: processDebugManifest 1. input/ouput 2. 整体流程 3. 调用链路 4. 核心类(MergeManifests) 5. AndroidBu ...

  7. Android构建流程——篇三

    文章目录 Task5 checkDebugManifest 1. input/ouput 2. 核心类(CheckManifest) Task6 generateDebugBuildConfig 1. ...

  8. 优酷 Android 构建速度优化实践

    作者:苏彦郊(木磊) Android 项目一般使用 gradle 作为构建打包工具,gradle 简洁.动态的功能特性为人津津乐道,同样,构建执行速度缓慢的缺陷也一直为人诟病. 近年来,随着优酷功能特 ...

  9. AndroidStudio目录结构 APP构建流程 Jenkins持续集成构建 Gradle介绍 Proguard混淆

    Android Studio目录结构 通常我们是将工程设置成project模式,这个模式下我们的工程有很多目录: .gradle:包含一些Gradle编译脚本,gradle是Google推荐的编译工具 ...

最新文章

  1. PHP获取毫秒时间戳,利用microtime()函数
  2. 基于互联网大脑架构的腾讯未来趋势分析[系列1]
  3. Codeforces 432E Square Tiling(结构体+贪婪)
  4. 通过scatter图寻找噪音
  5. 你真的理解CAP理论吗?
  6. SharePoint 2010 - User Profile Sync Service自动停止
  7. 使用Java调用默认浏览器打开指定网址
  8. python文本聚类分析作用_文本聚类应用意义
  9. 4.6 数值分析: P阶收敛的迭代法
  10. 翟菜花:中粮我买网,十年未出线
  11. [Unity2D入门教程]简单制作仿植物大战僵尸游戏之③完善Defender植物和Attacker的相关细节(脚本,碰撞体)
  12. HDU 1241 Oil Deposits(石油储藏)
  13. 2022最新鸽哒IM即时通讯系统源码+带安装教程
  14. 智能家居--domoticz配置和风天气 HTTP/HTTPS poller 的使用以及domoticz_updateDevice的介绍
  15. 离线编译安装lrzsz
  16. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccc
  17. Android 7.0 插卡后APN信息的加载流程、UI界面编辑APN的流程及Android中APN配置相关的漏洞
  18. su: warning: cannot change directory to : Permission denied ;-bash: bash_profile: Permission denied
  19. 安装EDEM出现There is a problem with this Windows Installer package问题
  20. 计算机控制面板的作用,什么是控制面板;它有什么作用?

热门文章

  1. java模拟浏览器不关闭会话_JSP实现浏览器关闭cookies情况下的会话管理
  2. python定义匿名函数关键字_Python(11):Python函数基础(定义函数、函数参数、匿名函数)...
  3. android-ultra-pull-to-refresh list,[Android]Ultra-Pull-To-Refresh之listview下拉刷新、上拉加载的用例...
  4. 在PPT的时候,发现用Python十几行代码就可以实现Logo换色
  5. 理解神经网络函数高频成分的收敛率界限
  6. 超细粒度分析XLNet中神奇的Attention Mask
  7. 文本分类和序列标注“深度”实践
  8. 一文详解Google最新NLP模型XLNet
  9. 5.2 使用pytorch搭建GoogLeNet网络 笔记
  10. POJ3614Sunscreen(优先队列+贪心)