Gradle 重点讲解
一、Gradle理论
Gradle,这是一个基于 JVM 的富有突破性构建工具。Gradle 正迅速成为许多开源项目和前沿企业构建系统的选择,同时也在挑战遗留的自动化构建项目。Gradle使用语言是Groovy。
适用于自动化地进行软件构建、测试、发布、部署、软件打包的项目。
对于Gradle在Android Studio里面的作用可以简单理解为:是一种项目构建工具。用过Eclipse的都知道Ant。Android Studio 替代了Eclipse(Android方面),Gradle就是替代了Ant执行编译,打包的过程。Gradle中,每一个待编译的工程都叫一个Project。每一个Project在构建的时候都包含一系列的Task。比如一个Android APK的编译可能包含:Java源码编译Task、资源编译Task、JNI编译Task、lint检查Task、签名Task、打包生成APK的Task等。一个Project到底包含多少个Task,其实是由编译脚本指定的插件决定。插件是什么呢?插件就是用来定义Task,并具体执行这些Task的东西。
下面我们就来简单了解一下这一过程。
二、Gradle基本内容
说到gradle,很多人会发现其实一个project可能包含很多个build.gradle。(至少两个一个是project根目录下面的,一个是module根目录下面的;如果你有多个module那么每个module下面对应有一个build.gradle)。我们先来讲一下project下的gradle。
如下图:
![](https://img.haomeiwen.com/i23587538/f2149ad623f22107.png)
1.project下的build.gradle
直接上project根目录下的build.gradle文件内容,大致说明已经有注释了,其余就不做详细说明了。
// Top-level build file where you can add configuration options common to all sub-projects/modules.
// project根目录下的build.gradle用于添加子工程或模块(所谓的module)共用的配置项。
// "buildscript"的类型为script block,而且是最上层的script block,用于配置Gradle的Project实例。
// 其API文档为https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:buildscript(groovy.lang.Closure)
// 其余的根script block有"allprojects", "dependencies", "configurations"等,更多的可见https://docs.gradle.org/current/dsl/的“Build script structure”一节。
// Script Block是一种method的调用,传入的参数为configuration closure。执行后会对Project的属性进行配置。
// 此处的"buildscript"用于配置Project的build script的classpath。
buildscript {
repositories {
// 代码托管库,可以从https://jcenter.bintray.com/下载对应的代码库
jcenter()
//同理于jcenter(),申明代码托管库Google,如果需要相应的代码库,那么就会去下载
google()
//有时你可能还会使用maven的代码托管库
//maven{ url 'https://jitpack.io'}
}
//这里面依赖的插件应用于整个project,不同于module下面的build.gradle只应用于当前的module
dependencies {
//声明了一个Gradle插件用来作为Android开发。3.2.1为gradle版本号
classpath 'com.android.tools.build:gradle:3.2.1'
// classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
2.module下的build.gradle(重点)
1).apply plugin,声明是Android应用程序还是库模块
//声明是Android程序,
//com.android.application 表示这是一个应用程序模块,可直接运行
apply plugin: 'com.android.application'
//apply plugin: 'walle' 标识这是一个库模块,是依附别的应用程序运行(美团的一个开源打包工具:瓦力)
附上官方文档apply方法说明:
![](https://img.haomeiwen.com/i23587538/aee0b82f69545aed.png)
2).android 闭包{},配置项目构建的各种属性(signingConfigs、defaultConfig、buildTypes、sourceSets、lintOptions、packagingOptions、compileOptions、productFlavors等),compileSdkVersion用于指定项目的编译SDK版本,buildToolsVersion用于指定项目构建工具的版本。这里说一下compileSdkVersion、buildToolsVersion、targetSdkVersion版本最好一致,当然buildtoolsVersion版本号可以高于编译sdk版本号和目标sdk版本号;比如下面这两种情况:
![](https://img.haomeiwen.com/i23587538/f4a9a098ba2573e9.png)
![](https://img.haomeiwen.com/i23587538/a961170dbd721f5e.png)
defaultConfig闭包{}:默认配置,应用程序包名(applicationId),最小 sdk 版本(minSdkVersion),目标 sdk 版本(targetSdkVersion),版本号(versionCode),版本名(versionName)等
defaultConfig {
//按需求添加相对应的属性
applicationId "com.admin.shopkeeper" //包名
minSdkVersion 16//最小sdkversion
targetSdkVersion 26//目标sdkversion
versionCode 32//版本号
versionName "1.31"//版本名
multiDexEnabled true//添加多分包支持
vectorDrawables.useSupportLibrary = true//库支持矢量图
flavorDimensions "color"//定义特点维度(简单理解为可能分为正式或测试;不同的渠道等特点)
}
productFlavors闭包{}:创建不同维度的app
productFlavors {
//1.比如说这种:就是按正式环境的地址和测试环境地址打成正式和测试版
t {
buildConfigField 'String', 'API_URL', '"https://www.xxx.com:8098/"'
buildConfigField 'String', 'APK_SUFFIX', '"-test"'
}
p {
buildConfigField 'String', 'API_URL', '"https://www.xxx.com:8099/"'
buildConfigField 'String', 'APK_SUFFIX', '""'
}
}
productFlavors {
//2.比如说这种:就是按照不同渠道来打包豌豆荚和百度
wandoujia {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
}
baidu {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
}
}
buildTypes闭包{}:指定生成安装文件的配置,是否对代码进行混淆等配置
buildTypes {
debug {
minifyEnabled false//是否进行混淆(no)
zipAlignEnabled false//Zipalign优化(no)
signingConfig signingConfigs.debug//签名配置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//混淆文件
shrinkResources false// 移除无用的resource文件
}
release {
minifyEnabled true//是否进行混淆(yes)
zipAlignEnabled true//Zipalign优化(yes),这样打出来的apk你会发现要小于不优化的apk
debuggable false
shrinkResources true// 移除无用的resource文件
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
signingConfigs 闭包{}:签名信息配置(上面讲到了签名信息配置,那我们接下来就说说配置签名信息),很多人都知道签名信息要保密特别是要上传svn,git管理工具这种更要注意;特别是git(毕竟build.gradle是要上传服务器的,如果不进行权限控制,项目私有化之类的很容易被别人看到),所以我们就把一般的配置信息放在gradle.properties文件下。下面让我们来看看这个文件:
//这个是gradle.properties文件的内容
android.enableAapt2=false
RELEASE_STOREFILE=E\:/NewAndroidStudioWeWe/WeWe_AS/WeWe_as/android_wewe.keystore//签名文件存储路径,这些请填写自己签名文件路径,密码,别名
RELEASE_STORE_PASSWORD =your store password//storePassword
RELEASE_KEY_ALIAS=wewe.keystore//别名
RELEASE_KEY_PASSWORD=your key password//keyPassword
接下来进入module下的build.gradle进行signingConfigs。
signingConfigs {
debug {
storeFile file(RELEASE_STOREFILE)//gradle.properties下的文件路径
storePassword RELEASE_STORE_PASSWORD///gradle.properties下的store密码
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD//gradle.properties下的key密码
}
}
sourceSets 闭包{}:源文件路径配置
sourceSets {
main {
jniLibs.srcDirs = ['libs']//设置so文件存放路径
}
}
lintOptions 闭包{}:lint 配置
//打包的时候会进行lint检查
lintOptions {
abortOnError false//报错也不会停止打包
checkReleaseBuilds false//checkReleaseBuilds就是在打包Release版本的时候进行检测,这里就直接关掉了,也可以打开,这样报错还会显示出来
// 防止在发布的时候出现因MissingTranslation导致Build Failed!
disable 'MissingTranslation'
}
compileOptions闭包{}:
android闭包里面再说一个吧,如果你使用的是jdk1.8(java8的新特性)那么请加上上面的编译选项compileOptions。
compileOptions {
//适配java8的新特性
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
其它的一些闭包配置就不一 一解释了,需要的查看官方文档;我会在文末给出链接。
3).repositories闭包{},仓库配置
4).dependencies 闭包{},指定当前项目的所有依赖关系,本地库依赖,远程库依赖,模块依赖以及远程依赖
本地库依赖:
//库依赖
dependencies {
/**下面讲解本地库的依赖方式*/
//可以指定依赖某一个或几个jar ,如下依赖2个jar包
api files('libs/jar包名.jar', 'libs/jar包名.jar')
//当然可以依赖本地libs目录下的所有jar包
api fileTree(include: ['*.jar'], dir: 'libs')
//如果你的libs目录下存在其他类型的库包,比如aar(后缀)
//api(name:'库名',ext:'库类型')如下:name为:tuia-2.1.0,ext为aar
api(name: 'tuia-2.1.0', ext: 'aar')
}
远程库依赖:
//接下来说一下远程库依赖
dependencies{
// 依赖明确的版本,标明group、name和version implementation group: 'com.meituan.android.walle', name: 'library', version: '1.1.6'
// 通常按照如下方式简写即可 api 'com.meituan.android.walle:library:1.1.6'
api 'com.meituan.android.walle:library:1.1.6'
// 也可以不指定版本,将version改为"+",当远程仓库有更新的版本后,构建时会拉取最新的版本。
// 好处是可以始终依赖最新的library;弊端是有可能library的改动导致编译不过或者功能变更不
// 稳定,因为每次都需要检查是否有最新版本,所以构建效率会低一些
api 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
}
本地module依赖:
//本地module依赖
dependencies {
//api project(':模块名'),这样就可以依赖同个project下的其他模块了
api project(':sdpSsplibrary')
api project(':PushSDK')
}
如下图这种形式:
![](https://img.haomeiwen.com/i23587538/dd60090451bedbec.png)
最后说一下由于从Android Gradle plugin 3.0开始,对于依赖包的配置方式,引入了implementation和api,使用Android Studio新建项目时,原来用compile的地方全部默认被替换成了implementation ,最好自己使用api。依赖配置方式还有:provided、api、apk、compileOnly、runtimeOnly。不同的配置方式有不同的意义,看自己的版本和需求配置。
implementation:
依赖包中依赖的library只能在依赖包内部使用,主工程无法访问依赖包依赖的library中的类和方法。使用场景:SDK开发中对第三方library有依赖,希望控制SDK的大小、不想因为和宿主工程引用的同一个依赖包版本不同导致编译冲突时特别适合。
因为当依赖包依赖的library有改动时,只会重新编译library和依赖包,不需要重新编译宿主,所以构建速度会快一些。
对于各个渠道还可以单独依赖属于渠道特有的包,通过渠道名+implementation指定,比如debugImplementation、releaseImplementation、testImplementation。
api(原compile):
会将依赖包中依赖的其它library一同编译和打包到apk中,宿主工程可以使用依赖包中依赖的其它library的类和方法。
对于各个渠道还可以单独依赖属于渠道特有的包,通过渠道名+api/compile指定,比如debugApi、releaseApi、testApi。
compileOnly(provided):
主要是为了方便程序编译通过的,不会打包到apk中,使用场景:android系统有这个API,但编译时需要引入才能构建通过,比如系统的APK依赖framework.jar、gson库等。
runtimeOnly(原apk):
只是打包到apk中,不参与编译,不能在代码中直接调用依赖包的代码,否则会在编译时出错。一般很少使用。
最后给上整个build.gradle文件的内容:
//声明是Android程序,
//com.android.application 表示这是一个应用程序模块,可直接运行
apply plugin: 'com.android.application'
//apply plugin: 'walle' 标识这是一个库模块,是依附别的应用程序运行
android {
useLibrary('org.apache.http.legacy')
signingConfigs {
wewekey {
storeFile file(RELEASE_STOREFILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
compileSdkVersion 19
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.xx.xx"
minSdkVersion 14
targetSdkVersion 19
}
buildTypes {
release {
minifyEnabled true
// proguardFiles 'proguard.cfg'
proguardFiles getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro"
//Zipalign优化
zipAlignEnabled true
// 移除无用的resource文件
shrinkResources true
signingConfig signingConfigs.wewekey
}
debug {
// 移除无用的resource文件
//debuggable true
minifyEnabled false
//shrinkResources true
testCoverageEnabled false
signingConfig signingConfigs.wewekey
proguardFiles getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro"
}
}
packagingOptions {
exclude 'META-INF/NOTICE.txt' // will not include NOTICE file
exclude 'META-INF/LICENSE.txt' // will not include LICENSE file
}
lintOptions {
abortOnError false
checkReleaseBuilds false
// 防止在发布的时候出现因MissingTranslation导致Build Failed!
disable 'MissingTranslation'
}
// sourceSets {
// main {
// jniLibs.srcDirs = ['libs'] //设置目标的so存放路径
// }
// }
}
allprojects {
repositories {
flatDir {
dirs 'libs'
}
}
}
dependencies {
api 'com.android.support:support-annotations:23.0.1'
api 'com.android.support:support-v4:19.1.0'
api 'com.meituan.android.walle:library:1.1.6'
api 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
api fileTree(include: ['*.jar'], dir: 'libs')
api(name: 'tuia-2.1.0', ext: 'aar')
// implementation files('libs/umeng-common-1.5.3.jar')
// implementation files('libs/umeng-analytics-7.5.3.jar')
}
/*
walle {
// 指定渠道包的输出路径
apkOutputFolder = new File("${project.buildDir}/outputs/channels");
// 定制渠道包的APK的文件名称
apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk';
// 渠道配置文件
channelFile = new File("${project.getProjectDir()}/channel")
}*/
大概就说这么多吧,如果还是不怎么明白,那么就查看官方文档以及相应的博客。感谢您看到这里,如果需要下一篇博客我就写walle的多渠道打包;不然就写几篇设计模式的博客。
本文在开源项目:https://github.com/Android-Alvin/Android-LearningNotes 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...