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

Project

Project实例

name

String

项目目录的名称。

path

String

项目的绝对路径。

description

String

项目的描述。

projectDir

File

包含生成脚本的目录。

buildDir

File

projectDir/build

group

Object

通常是application的label

version

Object

未指定

ant

AntBuilder

AntBuilder实例

task

一个简单task,可点击左边的开始按钮

Android gradle plugins分号 android gradle语法_android

执行;

task hello {
    return 'Hello world!'
}

也可以指明task依赖关系:

task dep(dependsOn: hello)  {
    println "I'm Gradle"
}

执行结果如下

Android gradle plugins分号 android gradle语法_gradle_02

循环执行任务

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'//排除不需要打包的文件
    }