Android 各种gradle文件笔记

571 阅读10分钟

Android 项目Gradle 解析

gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME    // 下载的Gradle压缩包解压后存储的主目录
distributionPath=wrapper/dists       // 相对于distributionBase的解压后的Gradle压缩包的路径。
zipStoreBase=GRADLE_USER_HOME        // 同distributionBase,只不过存放的是zip压缩包的
zipStorePath=wrapper/dists           // 同distributionPath,只不过存放的是zip压缩包的
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip  //Gradle发行版压缩包的下载地址。 其中gradle-6.5-all.zip 是包含源代码的,bin是不包含源代码的
  1. GRADLE_USER_HOME 默认路径是~/.gradle/, 不建议使用本地maven的m2替代
  2. 如果启动时,指定参数,使用彼得目录代替GradleUserHome, 后果是每次构建需要重新下载插件和依赖到新的目录。
  3. 默认情况下,gradle运行时,除了和项目打交道,还有当前项目要构建的全新GradleUserHome 目录,所有jar包都得重新下载。
Gradle命令行
  1. gradlew -?/-h/-help  使用帮助
  2. gradlew tasks 查看所有可执行的tasks
  3. gradlew --refresh-dependencies assemble 强制刷新依赖
  4. gradlew cBC等价于执行Task cleanBuildCache ,这种通过缩写名快速执行任务
  5. gradlew :app:dependencies 查找app工程依赖树
Gradle 构建机制
settings.gradle
  1. 支持多工程构建,使用settings.gradle来配置添加子工程(模块).
  2. settings 文件在初始化阶段执行,创建settings对象,在执行脚本时调用该对象的方法。
  3. settings.include(String ... projectPaths):
    • 将给定的目录添加到项目构件中,“:app”表示文件相对路径,相当于'./app' 文件夹。
    • 多项目架构进行分层,把同层次的子工程放在同一文件夹下便于管理,使用':xxx:yyy'表示。
build.gradle
  1. build.gradle 是项目构建文件,每个工程都有一个build.gradle 文件
  2. build.gradle   在配置阶段执行,并创建相应工程的project对象,执行的代码可以直接调用该对象提供的方法或属性。
Gradle 生命周期:
  1. 初始化: Gradle 支持单项目和多项目构建。在初始化阶段,Gradle确定哪些项目将参与构建,并为每个项目创建Project实例,一般我们不会接触到它。比如解析settings.gradle
  2. 配置阶段: 解析每个工程的build.gradle 文件,创建要执行的任务子集和确定各种任务之间的关系,并对任务做一些初始化配置。
  3. 执行阶段: Gradle 根据配置阶段创建和配置的要执行的任务子集,执行任务。
Gradle 执行流程

未命名文件.png

Gradle 钩子函数
  1. gradle 在生命周期三个阶段都设置了相应的钩子函数调用。
  2. 使用钩子函数,处理自定义的构建:
    • 初始化阶段:gradle.settingsEvaluatedgradle.projectsLoaded(在settings.gradle中生效)
    • 配置阶段:project.beforeEvaluateproject.afterEvaluate; grdale.beforeProjectgradle.afterProjectgradle.taskGraph.whenReady.
    • 执行阶段:gradle.taskGraph.beforeTaskgradle.taskGraph.afterTask.
Gradle 构建监听:

gradle 可以设置监听,对各阶段都有相应的回调处理。

  • gradle.addProjectEvaluationListener
  • gradle.addBuildListener
  • gradle.addListener
Configuration阶段
  1. 解析每个Project中的build.gradle,解析过程中并不会执行各个build.gradle 中的task
  2. 经过Configuration阶段,Project之间以及内部Task之间的关系就确定了。一个Project包含很多Task,每个Task之间有依赖关系。Configuration会建立一个有向图来描述Task 之间的依赖关系。所有Project 配置完成后,会有一个回调project.afterEvalutate(),表示所有的模块都已经配置好了。
Task
  1. task 是gradle 中最小的任务单元,任务之间可以进行复杂的操作( 动态创建任务,多任务之间的依赖调用等),gradle的执行其实就是由各种任务组合来执行,来对项目进行构建的。
  2. 使用gradlew help 命令,任何gradle项目都有一个该task,可以执行此命令观察task执行的流程是否如预期
  3. gradlw tasks --all 查看所有任务
DefaultTask
  1. task 定义的任务其实就是DefaultTask的一种具体实现类的对象。
  2. 可以使用自定义类继承DefaultTask: 
    • 在方法上使用@TaskAction 注解,表示任务运行时调用的方法。
    • 使用@Input表示对任务的输入参数
    • 使用@OutputFile表示任务输出文件。
    • 使用inputs,outputs直接设置任务输入/输出项
    • 一个任务的输出项可以作为另一个任务的输入项(隐士依赖关系)。
Project
  1. build.gradle在配置阶段会生成project实例,在build.gradle中直接调用方法或属性,实则是调用当前工程project对象的方法或属性。
  2. 使用Project 提供的api,在多项目构建设置游刃有余:
    • project(':app'){} 指定的project(这里是app)配置
    • allprojects{} 所有的project配置
    • subprojects{}所有的子project配置
    • buildscript{} 此项目配置构建脚本类路径。
属性扩展ext
  1. 使用ext对任意对象属性进行扩展:与局部变量的区别是别的project可见。

    • 对project使用ext进行属性扩展,对所有子project可见。
    • 一般在root project中进行ext属性扩展,为子工程提供复用属性,通过rootProject直接访问。
    • 任意对象都可以使用ext来添加属性:使用闭包,在闭包中定义扩展属性。直接使用=赋值,添加扩展属性。
    • 由谁进行ext调用,就属于谁的扩展属性。
    • 在build.gradle 中,默认是当前工程的project对象,所以在build.gradle直接使用"ext=" 或者"ext{}"其实就是给project定义扩展属性。
  2. 使用gradle.properties 以键值对形式定义属性,所有的project可直接使用。

Gradle 插件
  1. Gradle插件是提供给gradle构建工具,在编译时使用的依赖项。插件的本质就是对公用的构建业务进行打包,以提供复用。
  2. Gradle插件分为:脚本插件和二进制插件(实现Plugin的类)
  3. Gradle插件通过apply 方法引入到工程。
Gradle依赖管理

在大多数情况下,项目都要依赖lib形式的可重用功能,还有很多项目可能被切分成多个单独的子工程来构建模块系统。依赖管理是一种可以让项目自动化的定义、解析,以及使用依赖的技术。Gradle提供了强大的依赖管理支持。

Gradle资源库

在Gradle中存储模块的地方就叫资源库。

  1. 定义了资源库之后,Gradle就知道怎么样查找和检索模块。资源库有两种方式:本地库和远程库。
  2. 在运行时,如果相应的任务需要,那么Gradle就需要定位依赖的生命,依赖可能需要从远程库下载,也可以从本地库检索或者在多项目构建中的其他项目。这个过程就叫做依赖解析。
  3. 一旦解析,解析机制就会存储依赖的底层文件作为本地缓存,之后的构建会重用这些文件,而不用再到远程库下载。
  4. 模块还能提供一些其他的元数据,元数据是描述模块更详细信息的数据,比如在资源库中的坐标,项目的信息等。(group, name_version)。
添加依赖仓库
  • 在build.gradle 中使用allprojects{}对所有的工程进行配置,使用repositories{}添加依赖仓库。
  • google(): 添加一个在Google的Maven存储库中查找依赖项的存储库。
  • mavenCenteral(): 添加一个在Maven中央存储库中查找依赖项的存储库。
  • jcenter(): 添加一个在Bintray的Icenter存储库中查找依赖项的存储库。    NOTE: jcenter 即将关闭,需要迁移到mavenCenteral()
  • mavenLocal: 添加一个在本地Maven缓存中查找依赖项的存储库。
  • maven{}: 指定某个maven仓库的地址,使用url(path)方法来添加。
  • ivy{}: 指定某个ivy仓库地址,使用url(path)方法来添加。
Gradle依赖范围
  • 在Gradle构建脚本中开发者可以把依赖定义到不同的范围中,比如编译源码或者执行测试。在Gradle中依赖的范围叫依赖项配置。
  • Gradle插件内置了几种方式的依赖项配置。
  • 在build.gradle中使用dependencies{}添加依赖项。
自定义依赖项配置

添加自定义依赖项配置,就可以使用该依赖项配置添加依赖:

configurations {
    abc {
        println "abc"
    }
}
// 在dependencies{}中使用:abc 'androidx.core:core-ktx:1.2.0'
implementation
  • Gradle 会将依赖项添加到编译类路径,并将依赖项打包到构建输出。不过,当你的模块配置implementation依赖项时,会让Gradle了解你不希望该模块在编译时将该依赖项泄露给其他模块。也就是说,其他模块只有在运行时才能使用该依赖项。
  • 使用此依赖项配置代替api可以显著缩短构建时间,因为这样可以减少构建系统需要重新编译的模块数。例如,如果implementation依赖项更改了其API,Gradle只会重新编译该依赖项以及直接依赖于它的模块,大多数应用和测试模块都应该使用此配置。
api
  • Gradle会将依赖项添加到编译类路径和构建输出。当一个模块包含api依赖项时,会让Gradle了解该模块要以传递方式将该依赖项导出到其他模块,以便这些模块在运行时和编译时都可以使用该依赖项。
  • 此配置使用时应格外注意,只能对你需要以传递方式导出到其他上游消费者的依赖项使用它。这是因为,如果api依赖项更改了其外部API,Gradle会在编译时重新编译所有有权访问该依赖项的模块。因此,拥有大量的api依赖项会显著增加构建时间。除非要将依赖项的API公开给单独的模块,否则库模块应改用implementation依赖项。
annotationProcessor

如需添加对作为注解处理器的库的依赖,你必须使用annotationProcessor 配置将其添加到注解处理器的类路径。这是因为,使用此配置可以将编译类路径与注释处理器类路径分开,从而提高构建性能。

查看模块依赖项:
  • gradlew app:dependencies --configuration releaseRuntimeClasspath
  • x.x.x(*)该依赖已经有了,将不再重复依赖。
  • x.x.x ->x.x.x 该依赖的版本将被箭头所指的版本代替
  • x.x.x ->x.x.x(*)该依赖的版本被箭头所指的版本代替,并且该依赖已经有了,不在重复依赖。
解决依赖项冲突:

使用exclude 关键字

dependencies {
      implementation('some-library') {
            exclude group:'com.example.imgtools', module:'native' 
      }

 }

排除整个group

dependencies{
   implementation('some-library'){
        exclude group: 'com.example.imgtools'
    }
 }

使用全部排除

//在configurations{}  中添加下面节点
configurations {
    all*.exclude module: "support-fragment"
}
Force 强制指定
//强制指定版本

configurations.all{
    resolutionStrategy{
        force 'com.android.support:support-fragment:26.1.0'
    }
}
AGP(Android Gradle Plugin)

Android Studio 构建系统以Gradle为基础,并且Android Gradle插件添加了几项专用于构建Android应用的功能,虽然Android插件通常会Android Studio的更新步调保持一致,但插件可独立 于Android Studio运行并单独更新。

Android Studio 升级了----》AGP也需要升级----》Gradle 需要升级

resValue

使用resValue 可以为当前的构建产品增加资源文件属性

  格式: resValue 'string', 'name', 'value'

  注: string 表示资源标签的类型。name 表示资源属性名称,value 表示对应的属性值 name 如果已经存在,就不能进行覆盖。

不同的产品风味可以添加自己的resValue, 如果所有的产品都需要添加,则可以在defaultConfig{}进行添加。

buildConfigField
  • 使用buildConfigField 为产品修改BuildConfig中的类型。
  • BuildConfig是在产品构建时自动生成的java类,里面存放了一些静态常量,编译后可以直接使用类中的常量。
  • buildConfigField 'String', 'fieldName', '"value"'  注意: 字符串需要单引号+双引号
  • buildConfigField 'Boolean', 'fieldName', 'true'