闭包
对于gradle来讲,buildscript相当于一个方法,里面的内容相当于方法传递的参数,这实际上就是一个方法调用
如下,点进buildscript的源码,我们定位到了Project.java,发现buildscript其实就是一个参数为闭包的一个方法,
void buildscript(Closure configureClosure);
project/build.gradle
buildscript {
ext.kotlin_version = '1.4.10'
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.4'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
闭包和方法调用
如下,闭包和方法调用时等价的
//闭包写法
allprojects {
repositories {
mavenCentral()
maven { url 'https://maven.google.com' }
jcenter()
google()
maven { url "https://jitpack.io" }//使用数据库升级辅助GreenDaoUpgradeHelper时添加
}
}
//方法调用写法
allprojects(new Action<Project>() {
@Override
void execute(Project project) {
repositories {
mavenCentral()
maven { url 'https://maven.google.com' }
jcenter()
google()
maven { url "https://jitpack.io" }//使用数据库升级辅助GreenDaoUpgradeHelper时添加
}
}
})
方法讲解
buildTypes
android{
buildTypes{
test{
minifyEnabled false
...
}
release{
minifyEnabled true
...
}
}
}
假设我们想要在我们的某个页面做一个标记,开发人员能看到,测试人员看不到,我们可以这样做
- src下新建main同级别目录debug和release
- 在release和debug下新建同包文件BuildTypes.kt
- 在main下业务Activity中调用BuildTypes.kt中的方法,
- 这样随着在编译时构建类型的不同,运行时的表现也就不一样了
- 假设我们构建的是debug,实际执行的代码就是main+debug的代码
代码如下:
productFlavors
渠道纬度配置,假设我们为App配置中文版和英文版,可以添加以下代码,那么根据上面的配置,我们就有了cnDebug、cnRelease、enDebug、enRelease 4个构建类型了
//Gradle3.0版本开始需要配置渠道维度,不配置则报错
flavorDimensions 'language'
productFlavors{
cn{}
en{}
}
为了保证名称的App名称的本地化显示,我们可以在src下新建一个目录en,为我们的app配置不同的资源文件
src/en/res/values/strings
<resources>
<string name="app_name">Dsh_Android</string>
</resources>
而在main我们默认的目录下
<resources>
<string name="app_name">Dsh_安卓</string>
</resources>
多维度渠道配置
除了语言环境维度的不同,还可以扩展其他维度,比如渠道信息,那么我们可以这样写,现在我们有4x2 = 8个构建类型了,[cnXiaomiDebug,enXiaomiDebug,...]
//Gradle3.0版本开始需要配置渠道维度,不配置则报错
flavorDimensions 'language','market'
productFlavors{
cn{
dimension 'language'
}
en{
dimension 'language'
}
yingyongbao{
dimension 'market'
}
xiaomi{
dimension 'market'
}
}
dependencies
compile, implementation 和 api
- implementation:不会传递依赖
- compile / api:会传递依赖;api 是 compile 的替代品,效果完全等同
- 当依赖被传递时,二级依赖的改动会导致 0 级项目重新编译;当依赖不传递 时,二级依赖的改动不会导致 0 级项目重新编译
- 假设我们app主工程【0级】implementation依赖了lib1【1级】,lib1通过implementation依赖了lib2【2级】
- 由于lib1不传递依赖,所以app下是无法直接使用lib2中的类的
- 假设lib1通过api依赖了lib2【2级】
- 由于lib1传递了依赖,所以app下是直接可以使用lib2中的类的
这样做的原因是,lib1使用api依赖了lib2,那么app就间接依赖了lib2,这样app主工程每次编译的时候都需要重新编译lib2,这增加了打包构建的时间,而通过implementation不依赖lib2,那么打包时间会缩短。
这样做既有好处也有缺点,具体情况要具体分析
Gradle Wrapper
对应项目中的gradlew文件
- 通过「只同步版本,不同步文件」的方式来减小协作项目的大小 每个人电脑上的
- Gradle 存放在固定位置,然后使用 Gradle Wrapper 的配置来 取用对应的版本就行了
gradle-wrapper.properties
gradle-wrapper配置文件,真正的Gradle Wrapper是gradlew
settings.gradle
项目结构,包括module等
task
例:比如clean:清除项目的build目录
task clean(type: Delete) {
delete rootProject.buildDir
}
- 使用方法: ./gradlew taskName
- task 的结构:
task taskName {
初始化代码
doFirst {
task 代码
}
doLast {
task 代码
}
}
- doFirst() doLast() 和普通代码段的区别:
- 普通代码段:在 task 创建过程中就会被执行,发生在 configuration 阶段
- doFirst() 和 doLast():在 task 执行过程中被执行,发生在 execution 阶 段。如果用户没有直接或间接执行 task,那么它的 doLast() doFirst() 代码 不会被执行
- doFirst() 和 doLast() 都是 task 代码,其中 doFirst() 是往队列的前面插入代 码,doLast() 是往队列的后面插入代码
- 如下代码,最后输出为 -> 4213
task clean(type: Delete) { delete rootProject.buildDir doLast { println 1 } doFirst { println 2 } doLast { println 3 } doFirst { println 4 } //4213 }
- task 的依赖:可以使用 task taskA(dependsOn: b) 的形式来指定依赖。 指定依赖后,task 会在自己执行前先执行自己依赖的 task。
- 下面我们完成一个功能,每次更新版本前,都给当前的版本号+1,那么我们像下面这样写,这样我们每次打包前执行
./gradlew bumpVersionAndNotify
任务就可以了
task bumpVersion() { doLast { def versionPropsFile = file('version.properties') def versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) def codeBumped = versionProps['VERSION_CODE'].toInteger() + 1 versionProps['VERSION_CODE'] = codeBumped.toString() versionProps.store(versionPropsFile.newWriter(), null) } } task bumpVersionAndNotify(dependsOn: bumpVersion) { doLast { println "升级完成" } }
- 下面我们完成一个功能,每次更新版本前,都给当前的版本号+1,那么我们像下面这样写,这样我们每次打包前执行
gradle 执行的生命周期
三个阶段:
- 初始化阶段:执行 settings.gradle,确定主 project 和子 project
- 定义阶段:执行每个 project 的 bulid.gradle,确定出所有 task 所组成的有向无 环图
- 执行阶段:按照上一阶段所确定出的有向无环图来执行指定的 task
在阶段之间插入代码:
- 一二阶段之间:settings.gradle 的最后
- 二三阶段之间:project/build.gradle的最后
afterEvaluate {
插入代码
}