Android-Gradle(二) Gradle相关配置详解

557 阅读10分钟
原文链接: www.jianshu.com

参考资料:
mp.weixin.qq.com/s/1UHcYOudV…
mp.weixin.qq.com/s/hCXLz-9Bn…

1.Gradel简介

Gradle是一个项目自动化建构工具,它使用一种基于Groovy的特定领域语言来声明项目设置,而不是传统的XML。Gradle主要帮我们做了依赖,打包,部署,发布,各种渠道的差异管理等工作。当前其支持的语言限于Java、Groovy和Scala,计划未来将支持更多的语言。

Android Gradle 的 Project 和 Tasks

这个Gradle中最重要的两个概念。每次构建(build)至少由一个project构成,一个project 由一到多个task构成。项目结构中的每个build.gradle文件代表一个project,在这编译脚本文件中可以定义一系列的task;task 本质上又是由一组被顺序执行的Action`对象构成,Action其实是一段代码块,类似于Java中的方法

Android Gradle 构建生命周期

每次构建的执行本质上执行一系列的Task。某些Task可能依赖其他Task。哪些没有依赖的Task总会被最先执行,而且每个Task只会被执行一遍。每次构建的依赖关系是在构建的配置阶段确定的。每次构建分为3个阶段:

  • Initialization: 初始化阶段

这是创建Project阶段,构建工具根据每个build.gradle文件创建出一个Project实例。初始化阶段会执行项目根目录下的settings.gradle文件,来分析哪些项目参与构建。

所以这个文件里面的内容经常是:

image

这是告诉Gradle这些项目需要编译,所以我们引入一些开源的项目的时候,需要在这里填上对应的项目名称,来告诉Gradle这些项目需要参与构建。

  • Configuration:配置阶段

这个阶段,通过执行构建脚本来为每个project创建并配置Task。配置阶段会去加载所有参与构建的项目的build.gradle文件,会将每个build.gradle文件实例化为一个Gradle的project对象。然后分析project之间的依赖关系,下载依赖文件,分析project下的task之间的依赖关系。

  • Execution:执行阶段

这是Task真正被执行的阶段,Gradle会根据依赖关系决定哪些Task需要被执行,以及执行的先后顺序。
task是Gradle中的最小执行单元,我们所有的构建,编译,打包,debug,test等都是执行了某一个task,一个project可以有多个task,task之间可以互相依赖。例如我有两个task,taskA和taskB,指定taskA依赖taskB,然后执行taskA,这时会先去执行taskB,taskB执行完毕后在执行taskA.

那我们生成的task都在哪里呢?
答:点击你android studio 右上角的gradle按钮,如下:

image.png

里面的每一个条目都是一个task。
接下来就以自己平日练习的demo为例,进行讲解:
image.png

将项目模式切换为Android,然后查看Gradle Scripts目录就可以看到每个Module对应的bulid.gradle文件了,我们就先从gradle-wrapper.properties文件开始说起。

2.gradle-wrapper

首先Wrapper是对Gradle的一层包装,便于开发过程中统一Gradle构建的版本号,Gradle提供内置的Wrapper task帮助我们自动生成Wrapper所需的目录文件,那么Wrapper task帮我们自动生成了那些文件呢?如图:


image.png

还有我们项目里gradle\wrapper里的内容:


image.png

那下面我们看看gradle-wrapper.properties这个文件的内容即作用:
image.png

下面来说一下每一个字段及其说明

字段 字段的说明
distributionBase 下载Gradle压缩包解压后存储的主目录
distributionPath 相对于distributionBase解压后的压缩包的位置,默认都在c盘/用户/gradle路径下
zipStoreBase 和distributionBase类似,区别是存放zip压缩包
zipStorePath 和distributionPath类似,区别是存放zip压缩包
distributionUrl gradle压缩包的下载地址

distributionUrl下载路径下载的压缩包在本地的地址默认为:


image.png

此文件夹包含了各个版本你下载的Gradle。

3.settings.gradle

ok,我们先看看settings.gradle文件中都有哪些内容:


image.png

此文件一看便知:如果我们的Project依赖了N个本地的module那么此处就会有N个引入。

4.build.gradle(Project)

话不多说上图:

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
        mavenCentral()
        jcenter()
        //友盟新maven仓库地址
        maven { url 'https://dl.bintray.com/umsdk/release' }
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        //Butterknife插件依赖
        classpath 'com.jakewharton:butterknife-gradle-plugin:10.0.0'
    }

}

//Android 统一版本号管理
ext {
    //编译版本号
    globalCompileSdkVersion = 28
    //编译工具版本
    globalBuildToolVersion = "28.0.2"
    //当前sdk版本号
    globalTargetSdkVersion = 28
    //最低sdk版本号
    globalMinSdkVersion = 19
    androidDependencies = [
            design   : "com.android.support:design:${supportLibraryVersion}",
            appcompat: "com.android.support:appcompat-v7:${supportLibraryVersion}",
]
}

allprojects {
    repositories {
        google()
        mavenCentral()
        jcenter()
        //友盟新maven仓库地址
        maven { url 'https://dl.bintray.com/umsdk/release' }
        //BRVAH 框架引入
        maven { url "https://jitpack.io" }
        //Banner
        maven { url "https://www.jitpack.io" }

    }
}



task clean(type: Delete) {
    delete rootProject.buildDir
}

上面Project的build gradle文件中的代码都是Groovy语言,Groovy是基于JVM虚拟机的一种动态语言,它的语法和Java非常相似,它就是一门非常灵活的动态脚本语言。

Project的build gradle文件中的代码主要分五个部分来讲解:

4.1 buildscript

buildscript中的声明是gradle脚本自身需要使用的资源。可以声明的资源包括依赖项、第三方插件、maven仓库地址等.

4.2 ext

ext是自定义属性,本人现在喜欢将所有module公用的编译版本号,当前编译工具版本等公用的信息进行在project的build.gradle中进行自定义给所有module使用同一版本,方便管理。当然你也可以自定义一个Version.gradle文件,这样也可以在其中添加常用三方依赖库的版本信息,方便module统一调用,如果都在project的build.gradle中进行自定义东西太多,不方便,具体实现我就不说了。

4.3 repositories

repositories顾名思义就是仓库,而jcenter()、maven()和google()就是托管第三方插件的平台,平时开发中我们可能会遇到一些插件需要翻墙,也是在此配置。

4.4 dependencies

我们配置了repositories仓库后还需要在dependencies{}里面进行配置,把需要配置的依赖用classpath配置上,因为这个dependencies在buildscript{}里面,所以代表的是Gradle需要的插件。

4.5 task clean

task clean(type: Delete) {
    delete rootProject.buildDir
}

好多小小伙伴平时可以没太注意这个脚本的作用:

此脚本的作用是在运行gradle clean时,执行此处定义的task。该任务继承自Delete,意思是删除根目录中多余的build目录或文件。和Android Studio的clean差不多。

其实还有个疑问:buildscript中的repositories和allprojects中的repositories有什么区别呢?
答:
buildscript中的声明是gradle脚本自身需要使用的资源,而allprojects声明的却是你所有module所依赖的资源,比如你的每个module都需要用同一个第三库的时候,你可以在allprojects里面声明。

5.build.gradle(Module)

5.1 Gradle插件

首先我们先看:


image.png

这种叫做引入Gradle插件,而Gradle插件大致分为分为两种:
apply plugin:'×××':这种属于二进制插件,一般是被打包在jar里独自发布,如果你自定义过插件,你就会知道,通常在发布的时候要指定plugin id,默认为完全限定名。
apply from:'×××':叫做应用脚本插件,严格意义来说它属于一个脚本插件,和二进制插件不同的是它使用的是from关键字.后面紧跟的坫一个脚本文件,可以是本地的,也可以是网络存在的,如果是网络上的话要使用HTTP URL

Gradle插件的分类:
Gradle插件的主要分为三类:

  • App插件id:com.android.application.
    App插件id是App应用工程,它可以生成一个可运行的apk应用。
  • Library插件id:com.android.library.
    它可以生成AAR包给其他的App工程公用,就和我们的Jar一样,但是它包含了Android的资源等信息,是一个特殊的Jar包
  • Test插件id:com.android.test.
    最后一类是Test测试工程,用于对App工程或者Library库工程进行单元测试。

一般一个项目只会设置一个App插件,而module一般是会设置为Library插件,如果你学习过组件化你就会有一个清晰的认知。

5.2 Grade的基本配置

android {
    compileSdkVersion rootProject.ext.globalCompileSdkVersion

    defaultConfig {
        applicationId "com.hxzk_bj_demo"
        minSdkVersion rootProject.ext.globalMinSdkVersion
        targetSdkVersion rootProject.ext.globalTargetSdkVersion
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//打包只把英文和中文打包进去,其他忽略
        resConfigs 'zh','zh-rCN'  
          // 设置支持的 SO 库构架
            ndk {abiFilters "armeabi", "armeabi-v7a" }
        //此段代码解决的是因为引入了第三方jar包,而项目里方法数过多,需要分包,android项 
          目有方法数限制,最多64K。
          multiDexEnabled true
        //添加如下配置解决Butterknife 引起的Annotation processors must be explicitly declared now.
 javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
}
}
//声明下so文件的存放路径就行了,修改jniLibs的默认路径为libs
    sourceSets {
        main {
            //配置so加载目录
            jniLibs.srcDirs = ['libs']

        }
    }

我们一个来说明其含义:

android{}

是Android插件提供的一个扩展类型,可以让我们自定义Android Gradle工程,是Android Gradle工程配置的唯一入口

compileSdkVersion

是编译所依赖的Android SDK的版本

buildToolsVersion

是构建该Android工程所用构建工具的版本

defaultConfig{}

defaultConfig里面都是工程的默认配置

applicationId

配置我们的包名,包名是app的唯一标识。默认跟AndroidManifest里面的package包名一致,但其实他跟AndroidManifest里面的package是可以不同的,他们之间并没有直接的关系。
package指的是代码目录路径;applicationId指的是app对外发布的唯一标识,注意不要混淆。

minSdkVersion

是支持的Android系统的api level

targetSdkVersion

表明我们是基于哪个Android版本开发的,也就是开发版本

versionCode

app应用内部版本号,一般用于控制app升级

versionName

app应用的版本名称

resConfigs

通过resConfig指定我们需要的strings资源,包括过滤 drawable文件夹的资源等

multiDexEnabled

用于配置该BuildType是否启用自动拆分多个Dex的功能,通常用在方法数超过65535的解决办法

ndk{}

多平台编译,生成有so包的时候使用,包括四个平台'armeabi', 'x86', 'armeabi-v7a', 'mips'

sourceSets

Java源代码文件和资源文件的集合,我们可以通过sourceSets更改源集的Java目录或者资源目录等。


image.png
signingConfigs

签名配置,是标记该app的唯一性。storeFile签名文件,storePassword签名证书文件的密码,storeType签名证书类型,keyAlias签名证书中秘钥别名,keyPassword签名证书中改密钥的密码。
默认情况下,debug模式的签名已经被配置好了,使用的就是Android SDK自动生成的debug证书,它一般位于$HOME/.android/debug.keystore,其key和密码是已经知道的,一般情况下我们不需要单独配置debug模式的签名信息

buildType

构建类型,在Android Gradle工程中,它已经帮我们内置了debug和release两个构建类型,两种模式主要车别在于,能否在设备上调试以及签名不一样,其他代码和文件资源都是一样的

productFlavors

Gradle的多渠道打包,如下我们定义了yingyongbao 平台和yingyongbaovip 平台生成apk的名称。

productFlavors {
        yingyongbao {
 manifestPlaceholders = [APP_NAME: "APP普通版"]
}
yingyongbaovip {
manifestPlaceholders = [APP_NAME: "App付费版"]}
}
manifestPlaceholders

占位符,我们可以通过它动态配置AndroidManifest文件一些内容,譬如app的名字:



上面就是我们引用了在productFlavors 中定义的不同平台对应的应用名称。

buildConfigField
yingyongbao {
            manifestPlaceholders = [APP_NAME: "随意普通版"]
            buildConfigField("boolean", "isVipVersion", "false")
        }
yingyongbaovip {
            manifestPlaceholders = [APP_NAME: "随意付费版"]
            buildConfigField("boolean", "isVipVersion", "true")

        }

buildConfigField是BuildConfig文件的一个变量,而BuildConfig这个类是Android Gradle构建脚本在编译后生成的,生成的位置在:


image.png

那这个buildConfigField有什么作用呢?通常app针对不用的用户群体可能会出一个普通版和收费版,根据这个值去区分:


image.png
flavorDimensions

先上图:


image.png

image.png

flavorDimensions英文意思是维度,作用是可以在不同的包中形成不同的applicationId和versionName,也就是说可以生成两个app,在同一手机上测试。因为applicationId的值不同嘛,

dependencies{}

关于这个dependencies的含义及3.0之后如gradle 3.0中依赖implementation、api的区别,我上一篇文章有详解过,这里就不说了参考Android -Gradle依赖导入及相关知识