什么是构建工具呢,构建工具就是自动化帮我们完成一系列的编译打包的流程。
如果没有构建工具,我们就需要一遍一遍的执行命令去打包,比如打包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包,针对厂商适配可能还要再定制一个渠道包,又或者我需要修改一下版本号等等,这些都是通过配置来改的,具有一定的动态可配性。
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:构建流程:
-
初始化阶段:
- 执行 settings.gradle 构建脚本 , 查看当前的工程有哪些子模块 , 工程的顶层配置有哪些 , 如 rootProject.name 工程名称 ;
- 为每个 build.gradle 构建脚本 创建对应的 Project 实例对象 ;
-
配置阶段:会解析 工程根目录 和 每个模块 下的 build.gradle 构建脚本 , 确定 任务分组 , 任务之间的 依赖关系 , 执行顺序 等 , 然后对任务进行配置 ; 注意这里 只对任务进行配置 , 不会执行任务 ;
在 编写完 build.gradle 构建脚本 后 , 并 不会生成 Gradle 任务 , 在右侧的 Gradle 面板中找不到自定义的 Gradle 任务 , 需要点击 " Sync Now " 按钮 , 进行 配置阶段 操作 , 才会在右侧 Gradle 面板中 生成自定义的 Gradle 任务 , 并且 将指定的任务分配的指定的分组 , 任务间的依赖关系 , 执行先后顺序 也会进行处理配置 ; -
任务执行阶段: 在这个阶段,Gradle 开始执行定义的任务。任务可以是预定义的任务,也可以是自定义的任务。Gradle 会根据任务的依赖关系和执行顺序执行这些任务,以完成项目的构建流程。任务的执行可能涉及编译代码、运行测试、生成文档、打包文件等操作。
-
输出阶段: 一旦任务执行完成,Gradle 将生成的输出(例如编译后的类文件、资源、测试报告、打包的应用等)放入适当的目录中,以便在其他阶段使用。
-
构建缓存: Gradle 支持构建缓存,它可以缓存已构建的输出以便下次构建时重用。这有助于加快构建速度,特别是在多次构建之间代码没有变化的情况下。
-
结束阶段: 构建过程完成后,Gradle 会生成构建报告,其中包含了构建过程的详细信息,例如哪些任务被执行、花费的时间、产生的输出等。