1.Gradle简介
Gradle是一个基于JVM的构建工具,其 build 脚本使用 groovy dsl 编写。
Gradle 的核心在于基于 Groovy的丰富而可扩展的域描述语言(DSL)。 Groovy 通过声明性的语言元素将基于声明的构建推向下层,你可以按你想要的方式进行组合。
2.Project和task
projects 和 tasks是 Gradle 中最重要的两个概念。
任何一个 Gradle 构建都是由一个或多个 projects 组成。每个 project 包括许多可构建组成部分。 每个 project 都由多个 tasks 组成。每个 task 都代表了构建执行过程中的一个原子性操作。如编译,打包,生成 javadoc,发布到某个仓库等操作。
Project属性
名称 | 类型 | 默认值 |
| Project |
|
|
| 项目目录的名称。 |
|
| 项目的绝对路径。 |
|
| 项目的描述。 |
|
| 包含生成脚本的目录。 |
|
|
|
|
|
|
|
|
|
| AntBuilder |
|
task
一个简单task,可点击左边的开始按钮
执行;
task hello {
return 'Hello world!'
}
也可以指明task依赖关系:
task dep(dependsOn: hello) {
println "I'm Gradle"
}
执行结果如下
循环执行任务
task count {
doFirst {//doFirst,doLast是内置函数
4.times { print "$it " }
}
}
创建动态任务
4.times { counter ->
task "task$counter" {
doFirst{
println "I'm task number $counter"
}
}
}
task tout(dependsOn: task2){//打印出I'm task number 2
print "finish"
}
增加依赖:为已存在的任务增加行为
4.times { counter ->
task "task$counter" {
doFirst{
println "I'm task number $counter"
}
}
}
task2.dependsOn task1, task3
task tout(dependsOn: task2){//依次打印出I'm task number 1,3,2
print "finish"
}
以属性的方式访问任务,对于插件提供的内置任务。这尤其方便(例如:complie)
task hello{
println("helloKitty")
}
hello.doFirst{
println "task name is $hello.name"
}
为任务增加自定义属性
task myTask {
ext.myProperty = "myValue"
}
task hello{
print myTask.myProperty //打印出myValue
}
Gradle 允许在脚本中定义多个默认任务。在多项目构建中,每个子项目都可以指定单独的默认任务。如果子项目未进行指定将会调用父项目指定的的默认任务。
defaultTasks 'cleanD', 'runD'
task cleanD {
println 'Default Cleaning!'
}
task runD {
println 'Default Running!'
}
task other {//运行会先执行前两个任务
println "I'm not a default task!"
}
配置阶段后,Gradle 会了解所有要执行的任务 Gradle 提供了一个钩子来捕获这些信息。例如可以检查已经执行的任务中有没有被释放。借由此,你可以为一些变量赋予不同的值。
在下面的例子中,为 distribution 和 release 任务赋予了不同的 version 值。
gradle.taskGraph.whenReady {taskGraph ->
if (taskGraph.hasTask(releaseTask)) {
version = '1.0'
} else {
version = '1.0-SNAPSHOT'
}
}
3.依赖管理
android中的bulid.gradle有两种,一种是整个项目的,另一个是每个module中的。
下面先看整个项目的gradle:分为两个部分,buildscript{}中是编译过程中的配置;allprojects{}是整个项目需要依赖的仓库
buildscript {//编译过程配置
ext {//自定义属性,可通过rootProject.ext.x来引用
kotlin_version = '1.3.72'
}
repositories {//代码托管仓库
maven { url 'https://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' }
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61"
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
//配置整个项目依赖的仓库
repositories {
maven { url 'https://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' }
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
}
}
ext{}中是自定义的属性;
也可以在gradle.propertities中定义属性,如下代码定义了android编译版本,用于统一不同module的android版本
VERSION_TARGET_SDK=30
VERSION_COMPILE=30
VERSION_BUILD_TOOL=30.0.3
#图标
PROD_APP_ICON=@mipmap/ic_launcher
可通过如下方式引用
compileSdkVersion VERSION_COMPILE.toInteger() buildToolsVersion VERSION_BUILD_TOOL
然后看每个module中的bulid.gradle:
首先是插件的声明,根据plugin可以判断这个module是可运行的app或者是library
apply plugin: 'com.android.application'//通常在最顶部写
plugins {//应用插件的另一种写法
id 'com.android.library'
}
Android常见五种插件id:
plugin id | 描述 |
com.android.application | 应用程序插件,生成apk |
com.android.library | 库插件,生成aar,可供其它项目使用 |
com.android.test | 测试插件 |
com.android.feature | 创建Android Instant App时需要用到的插件 |
com.android.instantapp | Android Instant App的入口 |
依赖的添加:分为依赖本地SDK、依赖本地module、依赖远程库
implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])//依赖libs目录下的所有相关类型文件
implementation project(path: ':ZXingForAndroid')//依赖本地文件
implementation files('libs/Msc.jar')//依赖本地库
//远程依赖库
implementation('com.alibaba:QLExpress:3.2.0'){exclude group: 'com.android.support', module:'design' }// 加载时排除框架中的design包
依赖常用关键字
compile/implementation/api:编译范围依赖在所有的 classpath 中可用,同时它们也会被打包,其中compile与implementation相同,已废弃使用;api是可以在其它module中使用,例如module A、B都依赖C,A依赖B,则可以在B中使用api添加C的依赖,A中不必添加C的依赖。 implementation:依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要 JDBC API JAR,而只有在运行的时候才需要 JDBC 驱动实现。 compileOnly:只参与编译,不打包,常用于添加系统的库文件以通过编译。 testXXX:只用于测试。
4. Android中常用的gradle配置
defaultConfig块
用于默认配置,常用属性包括
minSdkVersion 21
targetSdkVersion 30
versionCode 2
versionName "1.0.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk.abiFilters 'arm64-v8a'//支持的ndk链接库类型
multiDexEnabled true //是否支持多dex
externalNativeBuild {}//ndk编译设置
此外,可以自定义BuildConfig属性
defaultConfig {
buildConfigField 'String','API_SERVER_URL','"http://url/"'
}
buildTypes块
用于构建不同的apk
buildTypes {
release {
minifyEnabled true //开启混淆
shrinkResources true //移除未使用资源
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release //设置使用的签名
}
debug {
debuggable true
}
custom {
minifyEnabled false
}
}
如上代码,可生成app-release,app-debug,app-custom三种apk。常用的属性如下
属性 | 描述 |
applicationIdSuffix | 配置applicationId的后缀 |
debuggable | 是否支持断点调试 |
jniDebuggable | 是否可以调试NDK代码 |
buildConfigField | 配置不同的开发环境,比如测试环境和正式环境 |
shrinkResources | 编译时是否移除未使用的资源,默认false |
zipAlignEnabled | 是否开启开启zipalign优化,提高apk运行效率 |
proguardFile | ProGuard混淆所使用的ProGuard配置文件 |
proguardFiles | 同时配置多个ProGuard配置文件 |
signingConfig | 配置签名信息 |
multiDexEnabled | 是否自动拆分多个Dex |
signingConfig块
signingConfigs {
debug {//可以在bulidTypes下的signingConfig中引用
storeFile file('release.keystore')//签名文件路径
storePassword 'xxxxxx'
keyAlias 'androidreleasekey'
keyPassword '123456'
}
release {
storeFile file('release.keystore')
storePassword 'xxxxxx'
keyAlias 'androidreleasekey'
keyPassword '123456'
}
}
productFlavors 多渠道打包配置
flavorDimensions 'default' // 定义产品维度,所有渠道都要指定维度
productFlavors {
dev {// 每个环境包名不同
applicationId DEVELOP_PACKAGE_NAME as String
dimension "default"
// 自定义buildConfig.java中的变量供代码中使用
buildConfigField "String", "MODE", '"develop"'
}
prod {
applicationId PROD_PACKAGE_NAME as String
dimension "default"
buildConfigField "String", "MODE", '"production"'
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders += [CHANNEL_VALUE: name]
if (name.equals('dev')) { //开发环境
flavor.manifestPlaceholders += [APP_NAME: DEV_APP_NAME as String]
flavor.manifestPlaceholders += [APP_ICON: DEV_APP_ICON as String]
flavor.manifestPlaceholders += ["apk.applicationId" : DEV_PACKAGE_NAME as String]
} else if (name.equals('prod')) { //生产环境
flavor.manifestPlaceholders += [APP_NAME: PROD_APP_NAME as String]
flavor.manifestPlaceholders += [APP_ICON: PROD_APP_ICON as String]
flavor.manifestPlaceholders += ["apk.applicationId" : PROD_PACKAGE_NAME as String]
}
//打包配置
applicationVariants.all { variant ->
def name = variant.flavorName
variant.outputs.all {//设置输出apk的文件名
if (name.equals('dev')){
outputFileName = "app-debug-${variant.versionName}.apk"
}else if (name.equals('prod')) {
outputFileName = "app-prod-${variant.versionName}.apk"
}
}
}
}
}
SourceSets配置
可以指定编译哪些源文件
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['src/main/jniLibs']
java {
exclude '/test/**' // 不想包含文件的路径
}
}
}
可以加逻辑判断,比如通过flag判断使用哪个manifest
sourceSets {
main {
if (DEBUG) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
NDK配置
1)defaultConfig{}中的 ndk.abiFilters 属性,配置ndk链接库支持的cpu架构
2)externalNativeBuild{}中配置cmake
externalNativeBuild {
cmake {
path "CMakeLists.txt"
cppFlags '-std=c++11'
arguments '-DANDROID_PLATFORM=android-21',
'-DANDROID_TOOLCHAIN=clang',
'-DANDROID_STL=c++_shared'
}
}
3)sourceSets中配置动态链接库的目录
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
4)android{}中的ndkVersion 属性,配置ndk版本号
发布到局域网私有仓库
在要发布的module的bulid.gradle中添加配置
apply plugin: 'maven'
//...其它配置
//将源码打包 为了保证引入的aar 包可以查看源码
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
}
//包含文档和源码的aar
artifacts {
archives androidSourcesJar
}
//上传到Maven仓库的task
uploadArchives {
repositories {
mavenDeployer {
//指定maven仓库url
repository(url: "http://10.10.25.223:8081/repository/maven-releases/") {
//nexus登录默认用户名和密码
authentication(userName: "admin", password: "123456")
}
pom.groupId = "com.test.camera"// 唯一标识(通常为模块包名,也可以任意)
pom.artifactId = "CameraMix" // 项目名称(通常为类库模块名称,也可以任意)
pom.version = "1.0.0" // 版本号
}
}
}
其它配置
compileOptions {//编译选项
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
checkReleaseBuilds false
abortOnError false
}
packagingOptions {
pickFirst 'lib/arm64-v8a/*.so'//解决重复引用库文件的问题
exclude 'META-INF/spring.schemas'//排除不需要打包的文件
}