Gradle构建流程

发布时间 2023-08-15 07:57:19作者: 蜗牛攀爬

什么是构建工具呢,构建工具就是自动化帮我们完成一系列的编译打包的流程。

如果没有构建工具,我们就需要一遍一遍的执行命令去打包,比如打包APK要用javac去编译代码,再用AAPT去编译资源文件,然后编译DEX组合APK最后签名,如果每改一次代码预览都要这么干的话,那肯定是相当费劲的,所以自动化构建工具就诞生了。同时,构建工具也帮助我们做依赖管理,比如在Android Studio之前,我们用Eclipse开发,没有构建工具的情况下,我们要依赖一个三方库,需要把jar包下载下来,然后再放进项目里,这个过程是比较繁琐的,而且在升级jar版本的时候又要重复操作一遍,如果其他项目要用的话,又要把这个jar包再手动复制一遍,但是Gradle是支持依赖传递的,通过不同的依赖方式就可以改变依赖作用域。

Gradle作为构建工具,主要是帮助我们编译打包apk的,apk是由各种文件组成的,比较多见的是代码文件和资源文件,那其实可以理解为Gradle本质上是在帮我们管理这些散落在各处的文件,比如代码文件有app目录下的源码、module、还有依赖的jar和aar等等,而配置可以决定我们依赖哪些代码,也可以决定哪些代码进入merge,以及打出来的apk产物是release还是debug,但是这类配置往往并不是固定不变的,它是根据开发人员的需求走的,比如提测用debug包,发布用release包,针对厂商适配可能还要再定制一个渠道包,又或者我需要修改一下版本号等等,这些都是通过配置来改的,具有一定的动态可配性。

Gradle中的所有内容都基于两个基本概念:项目(Project)和任务(Task)。每个Gradle构建都是由一个或多个project组成。每个project都是有一个或者多个任务组成。任务之间具有依赖关系,保证了任务的执行顺序。任务代表构建执行的一些原子工作。这可能是编译某些类,创建JAR,生成Javadoc或将一些jar或者aar文件发布到maven仓库。
groovy:
Groovy 说白了就是把写 Java 程序变得像写脚本一样简单。写完就可以执行,Groovy 内部会将其编译成 Java class 然后启动虚拟机来执行。当然,这些底层的渣活不需要你管。实际上,由于 Groovy Code 在真正执行的时候已经变成了 Java 字节码,所以 JVM 根本不知道自己运行的是 Groovy 代码.

Task

1:简单例子

task hello{
    print 'hello world'
}

执行./gradlew hello输出:

> Configure project :gradlepractice
hello world
> Task :gradlepractice:hello UP-TO-DATE

闭包:

task hello{
doLast{
print "do last "
}
doFirst{
print "do first "
}
print 'hellow test'
}

等同于:

task hello({
    doLast({
        print "do last "
    })
    doFirst({
        print "do first "
    })
    print 'hellow test'
})

 

2:Task最特殊的一个地方,他会涉及到2个不同的生命周期,配置期和执行期,而配置期的代码永远是先于执行期代码执行的;

由于前两句代码在doLast和doFirst方法中,所以,这两行代码的执行是在执行期,因此总是后于最后一句的输出

task hello{
    doLast{
        print "do last "
    }
    doFirst{
        print "do first "
    }
    print 'hellow test'
}

输出:

> Configure project :gradlepractice
hellow test
> Task :gradlepractice:hello
do first do last 
BUILD SUCCESSFUL in 646ms
1 actionable task: 1 executed

 

3:task依赖:B依赖A,执行B的时候,一定先执行A

task A{
    print 'AAAAAAAAAA'
}

task B(dependsOn: A){
    print 'BBBBBBBBBB'
}

输出:

> Configure project :gradlepractice
AAAAAAAAAABBBBBBBBBB
> Task :gradlepractice:A UP-TO-DATE
> Task :gradlepractice:B UP-TO-DATE

BUILD SUCCESSFUL in 896ms

 

 当我们用 Android Studio 进行安装包构建的时候,会发现其实是运行了一连串的 Task,也就是说其实是这些 task 的配合,最终构建出我们的 APK 的:

> Configure project :gradlepractice
> Task :aidlclient:preBuild UP-TO-DATE
> Task :aidlclient:preDebugBuild UP-TO-DATE
> Task :aidlclient:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :aidlvaslibrary:preBuild UP-TO-DATE
> Task :aidlvaslibrary:preDebugBuild UP-TO-DATE
> Task :aidlvaslibrary:packageDebugRenderscript NO-SOURCE
> Task :aidlclient:compileDebugRenderscript NO-SOURCE
> Task :aidlclient:dataBindingMergeDependencyArtifactsDebug
> Task :aidlclient:dataBindingMergeGenClassesDebug
> Task :aidlclient:generateDebugResValues
> Task :aidlclient:generateDebugResources
> Task :aidlvaslibrary:compileDebugRenderscript NO-SOURCE
> Task :aidlvaslibrary:generateDebugResValues
> Task :aidlvaslibrary:generateDebugResources
> Task :aidlvaslibrary:compileDebugAidl
> Task :aidlvaslibrary:packageDebugResources
> Task :aidlclient:compileDebugAidl NO-SOURCE
> Task :aidlclient:packageDebugResources
> Task :aidlclient:parseDebugLocalResources
> Task :aidlvaslibrary:parseDebugLocalResources
> Task :aidlclient:generateDebugBuildConfig
> Task :aidlclient:javaPreCompileDebug
> Task :aidlvaslibrary:writeDebugAarMetadata
> Task :aidlclient:createDebugCompatibleScreenManifests
> Task :aidlclient:extractDeepLinksDebug
> Task :aidlvaslibrary:extractDeepLinksDebug
> Task :aidlvaslibrary:generateDebugBuildConfig
> Task :aidlvaslibrary:javaPreCompileDebug
> Task :aidlvaslibrary:processDebugManifest
> Task :aidlvaslibrary:compileDebugLibraryResources
> Task :aidlclient:mergeDebugShaders
> Task :aidlclient:checkDebugAarMetadata
> Task :aidlvaslibrary:generateDebugRFile
> Task :aidlclient:processDebugMainManifest
> Task :aidlclient:processDebugManifest
> Task :aidlclient:compileDebugShaders NO-SOURCE
> Task :aidlclient:generateDebugAssets UP-TO-DATE
> Task :aidlvaslibrary:mergeDebugShaders
> Task :aidlvaslibrary:compileDebugShaders NO-SOURCE
> Task :aidlvaslibrary:generateDebugAssets UP-TO-DATE
> Task :aidlvaslibrary:packageDebugAssets
> Task :aidlclient:mergeDebugResources
> Task :aidlclient:mergeDebugAssets
> Task :aidlclient:mapDebugSourceSetPaths
> Task :aidlclient:compressDebugAssets
> Task :aidlclient:processDebugJavaRes NO-SOURCE
> Task :aidlvaslibrary:processDebugJavaRes NO-SOURCE
> Task :aidlvaslibrary:bundleLibResDebug NO-SOURCE
> Task :aidlclient:checkDebugDuplicateClasses
> Task :aidlclient:dataBindingGenBaseClassesDebug
> Task :aidlclient:mergeDebugJavaResource
> Task :aidlvaslibrary:compileDebugJavaWithJavac
> Task :aidlclient:desugarDebugFileDependencies
> Task :aidlvaslibrary:bundleLibCompileToJarDebug
> Task :aidlclient:processDebugManifestForPackage
> Task :aidlvaslibrary:bundleLibRuntimeToDirDebug
> Task :aidlclient:mergeDebugJniLibFolders
> Task :aidlvaslibrary:mergeDebugJniLibFolders
> Task :aidlvaslibrary:mergeDebugNativeLibs NO-SOURCE
> Task :aidlvaslibrary:copyDebugJniLibsProjectOnly
> Task :aidlclient:validateSigningDebug
> Task :aidlclient:writeDebugAppMetadata
> Task :aidlclient:writeDebugSigningConfigVersions
> Task :aidlclient:mergeDebugNativeLibs NO-SOURCE
> Task :aidlclient:stripDebugDebugSymbols NO-SOURCE
> Task :aidlclient:mergeLibDexDebug
> Task :aidlclient:mergeExtDexDebug
> Task :aidlclient:processDebugResources
> Task :aidlclient:compileDebugJavaWithJavac
> Task :aidlclient:dexBuilderDebug
> Task :aidlclient:mergeProjectDexDebug
> Task :aidlclient:packageDebug
> Task :aidlclient:createDebugApkListingFileRedirect
> Task :aidlclient:assembleDebug

位于C盘的.gradle目录:

依赖项下载和缓存: 当 Gradle 构建执行时,它需要下载项目所需的各种依赖项,包括库、插件和其他文件。这些文件会被下载到 .gradle/caches 子目录中,并以哈希值进行命名以防止冲突。已下载的依赖项将在缓存中保存,以便在将来的构建中重复使用,从而加快构建速度。

caches 子目录下,您可能会看到以下一些常见的子目录:

  • modules-2:这个目录存储 Gradle 依赖项的二进制文件,通常是 .jar 文件。每个依赖项都有一个哈希值命名的子目录,其中包含依赖项的二进制文件和元数据。

  • wrapper:如果项目使用了 Gradle Wrapper,那么 Gradle Wrapper 的相关文件和下载的 Gradle 版本会存储在这个目录中。

  • transform-1 目录:通常,这个目录用于存储从 Java 字节码转换为 Dalvik 字节码(Dex)的过程中生成的文件。这些文件包括 Dalvik 字节码、优化后的字节码、资源文件等。transform-1 目录中的文件名可能会使用哈希值等来确保唯一性和避免冲突。
  • transforms-2:这个目录存储 Android Gradle 插件进行的一些转换操作的缓存数据,如 Dex 转换。

  • transform-3 目录: 这个目录通常用于存储将多个 Dex 文件合并成一个或进行 Dex 优化的过程中生成的文件。在 Android Gradle 构建中,如果应用程序的方法数超过了 Dalvik 虚拟机的限制,构建系统会对多个 Dex 文件进行合并和优化,这就是 transform-3 目录的典型用途之一。
  •  

 

2:构建流程:

  1. 初始化阶段:

    • 执行 settings.gradle 构建脚本 , 查看当前的工程有哪些子模块 , 工程的顶层配置有哪些 , 如 rootProject.name 工程名称 ;
    • 为每个 build.gradle 构建脚本 创建对应的 Project 实例对象 ;
  2. 配置阶段:会解析 工程根目录 和 每个模块 下的 build.gradle 构建脚本 , 确定 任务分组 , 任务之间的 依赖关系 , 执行顺序 等 , 然后对任务进行配置 ; 注意这里 只对任务进行配置 , 不会执行任务 ;
    在 编写完 build.gradle 构建脚本 后 , 并 不会生成 Gradle 任务 , 在右侧的 Gradle 面板中找不到自定义的 Gradle 任务 , 需要点击 " Sync Now " 按钮 , 进行 配置阶段 操作 , 才会在右侧 Gradle 面板中 生成自定义的 Gradle 任务 , 并且 将指定的任务分配的指定的分组 , 任务间的依赖关系 , 执行先后顺序 也会进行处理配置 ;

  3. 任务执行阶段: 在这个阶段,Gradle 开始执行定义的任务。任务可以是预定义的任务,也可以是自定义的任务。Gradle 会根据任务的依赖关系和执行顺序执行这些任务,以完成项目的构建流程。任务的执行可能涉及编译代码、运行测试、生成文档、打包文件等操作。

  4. 输出阶段: 一旦任务执行完成,Gradle 将生成的输出(例如编译后的类文件、资源、测试报告、打包的应用等)放入适当的目录中,以便在其他阶段使用。

  5. 构建缓存: Gradle 支持构建缓存,它可以缓存已构建的输出以便下次构建时重用。这有助于加快构建速度,特别是在多次构建之间代码没有变化的情况下。

  6. 结束阶段: 构建过程完成后,Gradle 会生成构建报告,其中包含了构建过程的详细信息,例如哪些任务被执行、花费的时间、产生的输出等。