如图,

  • 编译器源代码(包括 Application Module 及其所依赖的所有 Library 源代码)转换成 DEXDalvik Executable)文件(其中包括运行在 Android 设备上的字节码),将所有其他内容转换成已编译资源。(

    • 源代码(包括 Application Module 和 Library Module)编译成 class 文件,再将所有的 class 文件(包括第三方库中)打包生成 dex 文件。
    • 解压所有 aar 包中的资源文件,并和项目中所有资源文件合并到一个目录。
    • 生成资源文件的索引文件。

  • APK 打包器DEX 文件和已编译资源打包生成单个 APK。不过,必须先对 APK 签名,才能将应用安装并部署到 Android 设备上。
  • APK 打包器使用 Debug 或 Release 密钥库对 APK 签名
    • 如果您构建的是 Debug 版本的应用(即专用于测试和分析的应用),打包器会使用 Debug 密钥库签名应用。Android Studio 自动使用 Debug 密钥库配置新项目。
    • 如果您构建的是打算向外发布的 Release 版本应用,打包器会使用 Release 密钥库签名应用。
  • 在生成最终 APK 之前,打包器会使用 zipalign 工具对应用进行优化减少其在设备上运行时的内存占用

2. Gradle 构建 tasks 说明

我们通过 Android Studio 的 build -> Build APK 功能来看下,build 过程中是怎样的。Build APK 会执行以下 Gradle task。 (注:这里是用 Debug 模式做例子,Release 模式时只需将 task 中的 Debug 替换成 Release 理解即可)
Executing tasks: [:app:assembleDebug]

:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:compileDebugAidl UP-TO-DATE
:app:compileDebugRenderscript UP-TO-DATE
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources UP-TO-DATE
:app:mergeDebugResources UP-TO-DATE
:app:transformDataBindingBaseClassLogWithDataBindingMergeGenClassesForDebug UP-TO-DATE
:app:dataBindingGenBaseClassesDebug UP-TO-DATE
:app:checkDebugManifest UP-TO-DATE
:app:generateDebugBuildConfig UP-TO-DATE
:app:prepareLintJar UP-TO-DATE
:app:mainApkListPersistenceDebug UP-TO-DATE
:app:createDebugCompatibleScreenManifests UP-TO-DATE
:app:processDebugManifest
:app:splitsDiscoveryTaskDebug UP-TO-DATE
:app:processDebugResources
:app:generateDebugSources
:app:dataBindingExportBuildInfoDebug
:app:javaPreCompileDebug UP-TO-DATE
:app:transformDataBindingWithDataBindingMergeArtifactsForDebug UP-TO-DATE
:app:compileDebugJavaWithJavac
:app:compileDebugNdk NO-SOURCE
:app:compileDebugSources
:app:mergeDebugShaders UP-TO-DATE
:app:compileDebugShaders UP-TO-DATE
:app:generateDebugAssets UP-TO-DATE
:app:mergeDebugAssets UP-TO-DATE
:app:transformClassesWithDexBuilderForDebug
:app:transformDexArchiveWithExternalLibsDexMergerForDebug
:app:transformDexArchiveWithDexMergerForDebug
:app:mergeDebugJniLibFolders UP-TO-DATE
:app:transformNativeLibsWithMergeJniLibsForDebug UP-TO-DATE
:app:processDebugJavaRes NO-SOURCE
:app:transformResourcesWithMergeJavaResForDebug UP-TO-DATE
:app:validateSigningDebug UP-TO-DATE
:app:packageDebug
:app:assembleDebug BUILD SUCCESSFUL in 20s
特别说明:由于 Gradle 会尝试通过不重复执行输入未发生变化的 task 来节省时间(这些 task 被标记为 UP-TO-DATE,如上所示)
所以第一次编译运行会比较久,而后面就不会了。

  

上面列出来的 Gradle 构建过程,大致可分为五个阶段

  1. Preparation of dependecies 在这个阶段 Gradle 检测 Module 依赖的所有 library 是否 ready。如果这个 Module 依赖于另一个 Module ,则另一个 Module 也要被编译。
  2. Merging resources and processing Manifest 打包资源Manifest 文件。
  3. Compiling 在这个阶段处理编译器的注解源码被编译成字节码
  4. Postprocessing 所有带 transform 前缀的 task 都是这个阶段进行处理的。
  5. Packaging and publishing 这个阶段 library 生成.aar文件,Application 生成.apk文件。

这五个阶段和上面的构建过程中 task 的时序有大致的对应关系,大家可以相互映照着理解。

为了便于大家理解,下面给出一些关键 task 的说明:

  • mergeDebugResources 解压所有的 aar 包输出到app/build/intermediates/exploded-aar,并且把所有的资源文件合并到app/build/intermediates/res/merged/debug目录里。

  • processDebugManifest 把所有 aar 包里的AndroidManifest.xml中的节点,合并到项目的AndroidManifest.xml中,并根据app/build.gradle中当前buildType 的 manifestPlaceholders配置内容替换 manifest 文件中的占位符,最后输出到app/build/intermediates/manifests/full/debug/AndroidManifest.xml

  • processDebugResources

    1. 调用 aapt 生成项目和所有 aar 依赖的R.java,输出到app/build/generated/source/r/debug目录;
    2. 生成资源索引文件app/build/intermediates/res/debug/resources-debug.ap_
    3. 符号表输出到app/build/intermediates/symbols/debug/R.txt
  • compileDebugJavaWithJavac 用来把 java 文件编译成 class 文件,输出的路径是app/build/intermediates/classes/debug

    编译的输入目录有

    • 项目源码目录,默认路径是app/src/main/java,可以通过 sourceSetsdsl 配置,允许有多个(打印project.android.sourceSets.main.java.srcDirs可以查看当前所有的源码路径,具体配置可以参考 android-doc,以及这里
    • app/build/generated/source/aidl
    • app/build/generated/source/buildConfig
    • app/build/generated/source/apt(继承javax.annotation.processing.AbstractProcessor做动态代码生成的一些库,输出在这个目录)的代码。
  • transformClassesWithMultidexlistForDebug这个任务在使用 Multidex 才会出现)它有两个作用

    • 扫描项目的AndroidManifest.xml文件和分析类之间的依赖关系,计算出那些类必须放在第一个 dex 里面,最后把分析的结果写到app/build/intermediates/multi-dex/debug/maindexlist.txt文件里面
    • 生成混淆配置项输出到app/build/intermediates/multi-dex/debug/manifest_keep.txt文件里

    项目里的代码入口是 manifestapplication 节点的属性 android.name 配置的继承自 Application 的类,在 Android 5.0 以前的版本系统只会加载一个 dex(classes.dex),classes2.dex .......classesN.dex 一般是使用android.support.multidex.MultiDex加载的,所以如果入口的 Application 类不在 classes.dex5.0 以下肯定会挂掉,另外当入口 Application 依赖的类不在 classes.dex 时初始化的时候也会因为类找不到而挂掉,还有如果混淆的时候类名变掉了也会因为对应不了而挂掉,综上所述就是这个任务的作用。

Android Studio 的 build 过程的更多相关文章

  1. 使用Android Studio调试UiAutomator过程中遇到的问题

    声明: 这里纪录了个人学习和使用Android Studio调试UiAutomator过程中遇到遇到的问题,不定时进行更新,欢迎一起交流学习 1.Excution faild for task ‘:a ...

  2. Android studio在使用过程中的问题总汇!

    使用android studio也有一段时间了,汇总了一下这段时间内遇到一些常见问题,希望能够帮助到大家! 一.字体大小问题 在android studio的使用过程中没有发现类似于Eclipse中的 ...

  3. 解决Android Studio Gradle Build Running慢的问题

    Android Studio方便好用,但是Android Studio Gradle Build Running很慢 解决方法: C:\Users\你的用户名\.gradle 目录下新建一个文件名为 ...

  4. 解决Android Studio Gradle Build特别慢的问题

    解决Android Studio Gradle Build 特别慢的问题 C:\Users\你的用户名\.gradle目录下新建一个文件名为gradle.properties的文件.内容为:org.g ...

  5. Android Studio Gradle Build Running 特别慢的问题探讨

    本文的本本win7 64bit 6G android studio2.1 在运行程序的时候Gradle Build Running 特别慢,一个helloworld都快2min了 1.开启gradle ...

  6. 如何用Android Studio查看build.gradle源码

    上一篇博客里讲过 build.gradle 里的每一行代码基本都是在调用一个方法,既然是这样,我们就可以用 android studio(下面简称as) 去查看它源码的方法注释说明,这样就可以理解每个 ...

  7. 第一次用上 Android Studio 2.3 过程及错误解决

    因为要开发Android5.0的缘故,抛弃了eclipse转到了Android Studio,第一次使用就是遇到了许多问题,终于是解决问题了,特意写一篇博文给各位要准备从eclipse转到Androi ...

  8. Android Studio 出现 Build gradle project info

    导入Android Studio,一直停留在Build gradle project info.主要是因为google被墙,下载gradle很慢,有时候设置下载不成功. 参考链接 http://blo ...

  9. 提高Android Studio的Build速度实践

    1.在下面的目录创建gradle.properties文件 /home/<username>/.gradle/ (Linux) /Users/<username>/.gradl ...

随机推荐

  1. Linux基础之常用命令整理(一)

    Linux 操作系统的安装 如今比较流线的linux操作系统 Centos Redhat  Fedora Ubuntu, 安装操作系统的提前是要有操作系统的镜像文件(.iso文件)并且必须为系统指定一 ...

  2. php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现

    php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现 function data_uri($contents, $mime) { $base64 = base64_encode($c ...

  3. Intellij IDEA快捷键大全汇总(2019更新)

    Intellij IDEA快捷键大全汇总(2019) Ctrl+Shift + Enter,语句完成“!”,否定完成,输入表达式时按 “!”键 Alt+回车 导入包,自动修正 Ctrl+N   查找类 ...

  4. gentoo hibernate

    首先修改内核: Power management and ACPI options ---> [*] Suspend to RAM and standby [*] Hibernation (ak ...

  5. .htaccess: Invalid command 'Header', perhaps misspelled or defined by a module not included in the server configuration

    php项目 .htaccess文件配置如下: #文件缓存时间配置 <FilesMatch ".(flv|gif|jpg|jpeg|png|ico|swf|js|css)$"& ...

  6. 深入理解Java虚拟机读书笔记2----垃圾收集器与内存分配策略

    二 垃圾收集器与内存分配策略 1 JVM中哪些内存需要回收?     JVM垃圾回收主要关注的是Java堆和方法区这两个区域:而程序计数器.虚拟机栈.本地方法栈这3个区域随线程而生,随线程而灭,随着方 ...

  7. 页面跳转、URL直接访问限制

    问题 URL控制是为了避免以下错误 当前页需要读取上一页缓存,但是当前页直接通过URL访问无法获得相应的缓存 当前页需要通过入口,清楚历史中保留的缓存,但是当前页直接通过URL访问没有清除 本质上是为 ...

  8. 百度学术导入endnote出现choose an import filter解决

    一般情况,我们在百度学术搜索一篇文章, 点击引用,出来一个 点击EndNote,将下载好的.enw双击出现 百度了一些,可以不使用百度学术,用pubmed,点击citation. 发现一个解决办法.在 ...

  9. pymysql -转自https://www.cnblogs.com/chenhaiming/p/9883349.html#undefined

    PyMysql的几个重要方法 connect函数:连接数据库,根据连接的数据库类型不同,该函数的参数也不相同.connect函数返回Connection对象. cursor方法:获取操作数据库的Cur ...

  10. JAVA_04

    * a:局部代码块 * 在方法中出现:限定变量生命周期,及早释放,提高内存利用率 * b:构造代码块 (初始化块) * 在类中方法外出现:多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并 ...