Gradle知识点记录

Gradle是Android Studio默认的构建工具,它提高了Android的开发效率,它的作用就是管理项目中的依赖、打包、编译


构建历史

  • Apache Ant
    Ant支持自动化打包逻辑
  • Apache Maven
    Maven比它多了自动下jar包,规范了打包逻辑,反而不好定制
  • Gradle
    Gradle既能自动下jar包,又能自己写脚本,而且脚本写起来比Ant便捷

maven仓库

  • maven仓库:本地仓库+远程仓库
  • 远程仓库:中央仓库+私服+其他
  • 中央仓库:jcenter+mavencentral
  • 私服:公司内部局域网

如果本地仓库没找到,会按照repositories中声明的仓库顺序,在私有仓库和中央仓库查找对应的类库,找到则将类库版本信息下载到本地仓库

POM

pom:全名Project Object Model 项目对象模型,用来描述当前maven项目发布模块的基础信息

举例(’com.android.tools.build:gradle:4.1.1’)
groupId 组织 / 公司的名称 com.android.tools.build
artifactId 组件的名称 gradle
version 组件的版本 4.1.1
packaging 打包的格式 aar

project build.gradle

1
2
3
4
5
6
7
8
9
10
buildscript {
repositories {
[Gradle 插件的仓库]
}
}
allprojects {
repositories {
[项目中所有模块依赖的仓库]
}
}

module build.gradle

1
2
3
repositories{
[当前模块依赖的仓库]
}

gradle支持的仓库类型

1
2
3
4
5
repositories{
maven { url '...' }
ivy { url '...' }
flatDir { dirs '...' }
}

常用的中央仓库:

1
2
3
google()
mavenCentral()
jCenter()

国内镜像 阿里云

1
2
3
maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}

Release和SNAPSHOT

版本名:Release版本:1.0.0,SNAPSHOT版本:1.0.0-SNAPSHOT
Release版本如果版本没有更新不需要每次都去下载,除非本地仓库被清除,
而SNAPSHOT版本每次编译都需要去中央仓库更新版本信息

  1. snapshot打版-SNAPSHOT是必需含有的,deploy会发布到snapshot库,不含有-SNAPSHOT则为release版本,会发布到release库。
  2. maven更新依赖时-SNAPSHOT是实时拉取,release 则不会。
  3. 同一版本号上传到nexus仓库时,snapshot可以上传成功,release会上传失败

maven私服搭建

去官网下载 maven私服启动器nexus
https://juejin.cn/post/7118646272323485709
https://central.sonatype.com

发布github仓库

github需配合jitpack使用https://jitpack.io/

项目级build.gradle

1
2
3
4
5
6
7
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
}
}

发布mavencentral

详见:发布Gradle插件


Wrapper

wrapper里定义了gradle的版本

举例:
我现在的这个项目用的gradle版本是5.4.1的,那么这个版本是跟我现在的工程绑定的。若今后构建这个工程时,它都会用我所绑定的gradle版本(避免版本兼容性问题)所以wrapper的作用就是会来检查在你构建这个工程的机器上有没有5.4.1这个版本。如果有就开始构建,没有就去下载这个版本。再举个例子,假如你现在从网上下载了一个项目,而这个项目它所绑定的gradle版本是5.1.1的,而你的机器现在只有5.4.1版本的gradle,那么当这个项目在你这台机器上构建的时候,wrapper就会看你机器上有没有5.1.1版本的gradle,发现没有的话就会去到所提供的url下载这个版本。

build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
}
}

allprojects {
repositories {
google()
mavenCentral()
}
}

buildscript
dependencies里面所要下载依赖的jar包都要去到repositories中所给你的仓库里去找

allprojects
buildscript下面的是gradle自身构建所需要的一些依赖;而allprojects下方的仓库则是给项目中的其他module去使用的,像app模块或者其他你自己新建的一些模块它们所需的依赖就是到allprojects下面所给的仓库里去找

gradle.properties和local.properties

local.properties
放的是一些系统配置(比如sdk路径)
gradle.properties
这里放的是一些全局的配置文件,比如【android.useAndroidX=true】就是当前项目启用AndroidX

settings.gradle

这里面包含了你的子项目,也就是你项目中的module,假如刚新建好的项目那么就只包含一个’app’ module;如果你新建了其他module,它也会包含在这里面。在构建的初始化阶段,settings.gradle会提供这次构建项目所要包含的哪些module。

settings.gradle 对应一个 Settings 对象
build.gradle 对应一个 Project 对象


依赖管理

添加依赖:app > build.gradle > dependencies

1
2
3
dependencies {
implementation 'com.xxx.xxx’
}

添加仓库:project > build.gradle

1
2
3
4
5
6
buildscript {
repositories {
google()
mavenCentral()
}
}

如果不是google、maven仓库的话,需要自己手动在repositories{ }里配置仓库地址,新建项目这俩默认就有了

添加仓库:project > setting.gradle

1
2
3
4
5
6
7
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}

Gradle7.0之后,repositories{ }配置由build.gradle迁移到settings.gradle文件

app > build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
plugins {
id 'com.android.application'
}

android { ... }

dependencies {
// Dependency on a local library module
implementation project(':mylibrary')
// Dependency on local binaries
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Dependency on a remote binary
implementation 'com.xxx.xxx’
}
  • 本地模块:需要在settings.gradle中include声明
  • 本地二进制文件:需要在build.gradle声明路径
  • 远端二进制文件:上述示例,也是用的最多的一种

Jcenter MavenCentral 区别

GAV(坐标): groupId + artifactId + version

api implementation 区别

  • implementation:模块内
  • api:具有依赖传递性,容易造成依赖冲突

./gradlew app:dependencies
可以查看依赖树
比如:androidx.annotation:annotation:1.1.0 -> 1.3.0
->:表示冲突,比如这个1.1.0 -> 1.3.0,-> 后面的版本表示Gradle决议之后的版本,
这里表示1.1.0版本被拉高到1.3.0


依赖决策

  • 同一个模块的多个相同依赖,优先选择最高版本
  • 多个模块的多个相同依赖,优先选择主模块(app)的版本,并默认有strictly关键字约束,
    即使子模块的版本比app模块的版本高,也优先选择主模块(app)中依赖的版本
  • force优先级高于strictly,如果二者同时显式声明,则会报错
  • 同时使用force强制依赖版本时,版本决议的结果跟依赖顺序有关,最早force的版本优先
  • 子级跟随父级:没有直接依赖okhttp的情况下,有多个retrofit依赖,okhttp的版本跟随高版本的retrofit

分类示例决议结果说明

  • 全数字,段数不同1.2.3 vs 1.41.4段数依次比较,数字大的胜出
  • 全数字,段数相同,位数相同1.2.3 vs 1.2.41.2.4同上
  • 全数字,段数相同,位数不同1.2.3 vs 1.2.101.2.10同上
  • 全数字,段数不同1.2.3 vs 1.2.3.01.2.3.0段数多的胜出
  • 段数相同,字母比较1.2.a vs 1.2.b1.2.b字母大的胜出
  • 段数相同,数字与非数字1.2.3 vs 1.2.abc1.2.3数字优先字母

Gradle插件

  • 脚本插件:.gradle为后缀的文件,通过 apply from去引用
  • 对象插件:实现org.gradle.api.plugins 接口的插件
  • 自定义对象插件:
    1、在 build.gradle 文件中直接编写
    2、在 buildSrc 默认插件目录下编写
    3、在自定义项目下编写
    然后通过 apply plugin 的方式去引用这个插件

详情可查看【发布Gradle插件java】和【发布Gradle插件kotlin】


Gradle bug

出现诡异的gradle问题,可以删除gradle重新编译
比如:rm -r ~/.gradle/wrapper/dists/gradle-6.5-bin


参考文章:
https://juejin.cn/post/7215579793261117501
https://juejin.cn/column/7123935861976072199