在使用Android Studio过程当中没少被Gradle坑过,虽然网上有不少简单粗暴的解决方案,但极少会说清楚原因,因此一直想看一本叫《Android Gradle权威指南》。 不过因为书中实践内容不少,更像一本工具书,并且Gradle现已发行了好几版,所以本篇仅仅是陈列出一些大的要点,尤为是那些熟悉又陌生的名词,若是想要具体了解细节和操做流程,必定要跟着书探索哟~html
一.Gradle入门java
1.本书环境python
- JDK:OpenJDK 1.8.0
- Gradle:Gradle 2.14.1 All 版
- IDE:Android Studio 2.2.3
- Android Plugin:Android Gradle 2.2.3
- Android:API 23
2.Eclipse和Android Studioandroid
a.开发配置区别:git
b.Eclipse迁移到AndroidStudio两种方式:api
3.Gradle的ZIP解压后目录安全
- docs:API、 DSL、指南等文档
- init.d:gradle初始化脚本目录
- lib:相关库
- media:一些icon资源
- samples:示例
- src:源文件
- getting-started.html:入门连接
- LICENSE
- NOTICE
![]()
4.引例:Gradle版Hello World服务器
//build.gradle:
task hello{//定义一个任务Task名为hello
doLast{//添加一个动做Action,表示在Task执行完毕后回调doLast闭包中的代码
println'Hello World'//输出字符串,单双号都可
}
}
//终端:
gradle hello//执行build.gradle中名为Hello的任务
//输出:
Hello World
复制代码
5.Gradle Wrapper闭包
a.含义:对Gradle一层包装,便于使用统一Gradle构建app
b.目录结构:
|--gradle
| |--wrapper
| |--gradle-wrapper.jar
| |--gradle-wrapper.properties
|--gradlew
|--gradlew.bat
复制代码
gradle-wrapper.jar
:具体业务逻辑实现的jar包gradle-wrapper.properties
:配置文件,包含篇配置信息以下图:
gradlew
:Linux下可执行脚本gradlew.bat
:Windows下可执行脚本c.经常使用命令:
gradle wrapper
,由Wrapper Task生成gradle wrapper --gradle-version XXX
用于指定使用的Gradle版本gradle wrapper --distribution-url XXX
用于指定下载Gradle发行版的url地址task wrapper(type:Wrapper){ //配置信息 }
6.Gradle日志
a.日志级别:
println 'XX'X
gradle -q tasks
7.Gradle命令行
./gradlew tasks
./gradlew --refresh-dependencies assemble
./gradlew clean jar
./gradlew -?
或./gradlew -h
或./gradlew -help
二.Groovy基础
一句话代表Groovy的地位:Groovy于Gradle,比如Java于Android
1.特性:Groovy是个灵活的动态脚本语言,语法和Java很类似,又兼容Java,且在此基础上增长了不少动态类型和灵活的特性,如支持闭包和DSL
2.语法
task printStringVar << {
def name = "张三”
println '单引号的变量计算:${name}'
println "双引号的变量计算:${name}"
}
运行./gradlew printStringVar输出结果:
单引号的变量计算:${name}
双引号的变量计算:张三
复制代码
//List
task printList<<{
def numList = [1,2,3,4,5,6];//定义一个List
println numList[1]//输出第二个元素
println numList[-1]//输出最后一个元素
println numList[1..3]//输出第二个到第四个元素
numList.each{
println it//输出每一个元素
}
}
//Map
task printlnMap<<{
def map1 =['width':1024,'height':768]//定义一个Map
println mapl['width']//输出width的值
println mapl.height//输出height的值
map1.each{
println "Key:${it.key},Value:${it.value}"//输出全部键值对
}
}
复制代码
//以集合的each方法为例,接受的参数就是一个闭包
numList.each({println it})
//省略传参的括号,并调整格式,有如下常见形式
numList.each{
println it
}
复制代码
task helloJavaBean<<{
Person p = new Person()
p.name = "张三"
println "名字是: ${p.name}"//输出类属性name,为张三
println "年龄是: ${p.age}"//输出类属性age,为12
}
class Person{
private String name
public int getAge(){//省略return
12
}
}
复制代码
//单个参数
task helloClosure<<{
customEach{
println it
}
}
def customEach(closure){
for(int i in 1..10){
closure(i)
}
}
//多个参数
task helloClosure<<{
eachMap{k,v->
println "${k} is ${v}"
}
}
def eachMap(closure){
def map1 = ["name":"张三","age":18]
map1.each{
closure(it.key,it.value)
}
}
复制代码
1.Settings文件
settings.gradle
,放在Project下//添加:app和:common这两个module参与构建
include ':app'
project(':app').projectDir = new File('存放目录')
include':common'
project(':common').projectDir = new File('存放目录')
复制代码
2.Build文件
build.gradle
:整个Project的共有属性,包括配置版本、插件、依赖库等信息build.gradle
:各个module私有的配置文件
3.Gradle任务
a.含义:指原子性操做
b.关系:一个Gradle可包含多个Project,一个 Project可包含多个Task,即每一个Project是由多个Task组成的;Task是Project的属性,属性名就是任务名
c.建立
def task myTask = task(myTask)
myTask.doLast{
println "第一种建立Task方法,原型为Task task(String name) throws InvalidUserDataException"
}
复制代码
def task myTask = task(myTask,group:BasePlugin.BUILD_GROUP)
myTask.doLast{
println "第二种建立Task方法,原型为Task task(String name,Map<String,?> args) throws InvalidUserDataException"
}
复制代码
task myTask{
doLast{
println "第三种建立Task方法,原型为Task task(String name,Closure configureClosure)"
}
}
复制代码
以上建立方式实际上最终都会调用
TaskContainter#create()
方法,使用./gradlew myTask
命令执行任务
d.访问
名称.方法
tasks['名称'].方法
tasks.getByPath('路径/名称')
,若不存在会抛出UnknownTaskException异常tasks.findByPath('路径/名称')
,若不存在返回nulltasks.getByName('名称')
,若不存在会抛出UnknownTaskException异常tasks.findByName('名称')
,若不存在返回null可见任务名称是惟一的,这是由于TaskContainer的父类 NamedDomainObjectCopllection是个具备惟一不变名字的域对象的集合
e.依赖:在建立任务时经过dependsOn指定其依赖的任务,能够控制任务的执行顺序
task task1<<{
println 'hello'
}
task task2<<{
println 'world'
}
//依赖单个任务
task task3(dependsOn:task1){
doLast{
println 'one'
}
}
//依赖多个任务
task task4{
dependsOn task1,task2
doLast{
println 'two'
}
}
复制代码
当执行task4时,会发现task一、task2会先执行,再执行task4
注:操做符<< 用在Task定义上至关于doLast
f.排序:除了经过强依赖来控制任务的执行顺序,还能够经过 shouldRunAfter
和 mustRunAfter
实现
taskB.shouldRunAfter(taskA) //表示taskB应该在taskA执行以后执行,有可能不会按预设执行
taskB.mustRunAfter(taskA) //表示taskB必须在taskA执行以后执行
复制代码
g.分组& 描述:分组是对任务的分类,便于归类整理;描述是说明任务的做用;建议两个一块儿配置,便于快速了解任务的分类和用途
def task myTask = task(myTask)
myTask .group = BasePlugin.BUILD_GROUP
myTask .description = '这是一个构建的引导任务'
复制代码
h.启用 & 禁用:enable属性能够启动和禁用任务,执行被禁用的任务输出提示该任务被跳过
def task myTask = task(myTask)
myTask.enable = false //禁用任务
复制代码
i.执行分析:执行Task的时候其实是执行其拥有的actions List,它是Task对象实例的成员变量;在建立任务时Gradle会解析其中被TaskAction注解的方法做为其Task执行的action,并添加到 actions List,其中doFirst和doList会被添加到action List第一位和最后一位
4.自定义属性
Project、Task和SourceSet都容许用户添加额外的自定义属性、并对自定义属性进行读取和设置
//给Project添加自定义属性
ext.age = 18
ext{
phone = 13888888888
address = 'Beijing'
}
//给Task添加自定义属性
task customProperty {
ext.inner = 'innnnnner'
doLast{
println project.hasProperty('customProperty') //true
println project.hasProperty('age') //true
println project.hasProperty('inner')//返回fasle
println "${age}"
println "${phone}"
println "${inner}"
}
}
复制代码
四.Gradle插件
1.做用
Gradle自己内置许多经常使用的插件,如若须要还能够扩展示有插件或者自定义插件,如Android Gradle插件就是基于内置的Java插件实现的
2.扩展示有插件
a.插件种类
org.gradle.api.Plugin
接口的插件,能够有plugin idb.应用插件:经过Project#apply()
方法,有三种用法
void apply (Map<String, ?> options)
apply plugin:'java'
apply plugin:org.gradle.api.plugins.JavaPlugin
apply plugin:JavaPlugin
apply from:'version.gradle'
apply plugin:'com.android.application'
注意:应用第三方发布的做为jar的二进制插件时,必须先在
buildscript{}
配置其classpath才能使用,不然会提示找不到该插件
//buildscript:为项目进行前提准备和初始化相关配置依赖
buildscript {
repositories {
jcenter ()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0"
}
}
apply plugin:'com.android.application
复制代码
void apply (Closure closure)
apply {
plugin:'java'
}
复制代码
void apply (Action<? super ObjectConfigurationActicn> action)
3.自定义插件:实现Plugin接口、重写apply()方法
1.项目结构
使用Java插件要先应用进来:
apply plugin:'java'
复制代码
此时会添加许多默认设置和约定,好比有如下默认项目结构:
|-example
| |-build.gradle
| |-src
| |-main
| |-java 源代码存放目录
| |-resources 打包文件存放目录
| |-test
| |-java 单元测试用例存放目录
| |-resources 单元测试中使用的文件
复制代码
2.源集(SourceSet)
sourceSets
属性(是一个SourceSetsContainer)和sourceSets{}
闭包好比,在上述Java插件默认项目结构中的main和test就是内置的两个源集,如今更改main源集的Java源文件的存放目录到src/java下:
apply plugin:'java'
sourceSets{
main{
java{
srcDir 'src/java'
}
}
}
复制代码
sourceSets{}
闭包添加apply plugin:'java'
sourceSets{
vip{
}
}
复制代码
此时会新建两个目录:src/vip/java和src/vip/resources
补充:除了SourceSet,Java插件里经常使用的其余属性:
![]()
3.配置第三方依赖
a.依赖方式
b.具体方法
repositories{}
闭包里声明依赖库的位置dependencies{}
闭包添加依赖
group:name:version
project('项目名称')
files('文件名称')
,多个文件逗号分开,或者fileTree(dir:'文件名称',include:'*.扩展名称')
依赖指定文件夹下指定扩展名文件举例:
apply plugin:'java'
repositories {
//外部依赖 依赖Maven中心库
maveCentral()
}
dependencies {
//外部依赖 完整写法
compile group:'com.squareup.okhttp3',name:'okhttp', version:'3.0.1'
//外部依赖 简单写法
compile 'com.squareup.okhttp3:okhttp:3.0.1'
//外部依赖 指定main源集依赖
mainCompile 'com.squareup.okhttp3:okhttp:3.0.1'
//项目依赖
compile project(':example')
//文件依赖 依赖libs下两个Jar包
compile files('libs/example01.jar', 'libs/example02.jar')
//文件依赖 指定依赖libs下全部Jar包
compile fileTree(dir: 'libs',include: '*.jar')
}
复制代码
4.内置任务
经常使用几种任务:
build
任务:构建项目clean
任务:删除build目录及构建生成的文件assemble
任务:不执行单元测试,只编译和打包check
任务:只执行单元测试javadoc
任务:生成Java格式的doc api文档还有些通用任务、对源集适用的任务:
5.多项目构建
settings.gradle
配置管理多项目;在每一个项目都有一个build.gradle
,采用项目依赖就能实现多项目协做//settings.gradle
include ':app'
project(':app').projectDir = new File('存放目录')
include ':base'
project(':base').projectDir = new File('存放目录')
//app/build.gradle
apply plugin:'java'
dependencies {
compile project(':base')
}
复制代码
6.发布构件
artifacts{}
闭包配置须要发布的构建,在uploadArchives{}
上传发布构件//以发布jar构件为例
apply plugin:'java '
task publishJar(type:Jar)
artifacts{
archives publishJar
}
uploadArchives{
repositories{
//发布到本地目录
flatDir{
name 'libs'
dirs "$projectDir/libs"
}
//发布到本地Maven库
mavenLocal()
}
}
复制代码
1.概述
Android Gradle插件继承于Java插件,具备Java插件的全部特性,也有本身的特性,看下官方介绍:
2.插件分类
com.android.application
com.android.library
com.android.test
3.项目结构
|-example
| |-build.gradle
| |-example.iml
| |-libs
| |-proguard-rules.pro 混淆配置文件
| |-src
| |-androidTest
| |-java Android单元测试代码
| |-main
| |-java App主代码
| |-res 资源文件
| |-AndroidManifest.xml 配置文件
| |-test
| |-java 普通单元测试代码
复制代码
4.内置任务
connectedCheck
任务:在全部链接的设备或者模拟器上运行check检查deviceCheck
任务:经过API链接远程设备运行checkslint
任务:在全部ProductFlavor上运行lint检查install
、uninstall
任务:在已链接的设备上安装或者卸载AppsigningReport
任务:打印App签名androidDependencies
任务:打印Android 依赖5.应用实例
//应用插件,Android Gradle属于Android发布的第三方插件
buildscript{
repositories{
jcenter()
}
dependencies{
classpath 'com.android.tcols.build:gradle:1.5.0'
}
}
apply plugin:'com.android.application'
//自定义配置入口,后续详解
android{
compileSdkVersion 23 //编译Android工程的SDK版本
buildToolsVersion "23.0.1" //构建Android工程所用的构建工具版本
defaultConfig{
applicationId "org.minmin.app.example"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes{
release{
minifyEnabled false
proguardFiles getDefaultPraguardFile('proguard-andrcid.txt'), 'proguard-rules.pro'
}
}
}
//配置第三方依赖
dependencies{
compile fileTree(dir:'libs', include:['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcorpat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
}
复制代码
a.defaultConfig
属性名 | 含义 |
---|---|
applicationId | 指定App包名 |
minSdkVersion | 指定App最低支持的Android SDK |
targetSdkVersion | 指定基于的Android SDK |
versionCode | 配置Android App的内部版本号 |
versionName | 配置Android App的版本名称 |
testApplicationId | 配置测试App的包名,默认为applicationId + “.test” |
testInstrumentationRunner | 配置单元测试使用的Runner,默认为android.test.InstrumentationTestRunner |
proguardFile | 配置App ProGuard混淆所使用的ProGuard配置文件 |
proguardFiles | 同时配置多个ProGuard配置文件 |
signingConfig | 配置默认的签名信息,也是一个ProductFlavor,可直接配置 |
b.buildTypes
assemble<BuildTypeName>
任务属性名 | 含义 |
---|---|
applicationIdSuffix | 配置基于默认applicationId的后缀 |
debuggable | 是否生成一个可供调试的Apk |
jniDebuggable | 是否生成一个可供调试JNI代码的Apk |
minifyEnabled | 是否启用Proguard混淆 |
multiDexEnabled | 是否启用自动拆分多个Dex的功能 |
zipAlignEnabled | 是否开启开启zipalign优化,提升apk运行效率 |
shrinkResources | 是否自动清理未使用的资源,默认为false |
proguardFile | 配置Proguard混淆使用的配置文件 |
proguardFiles | 同时配置多个ProGuard配置文件 |
signingConfig | 配置默认的签名信息,也是一个ProductFlavor,可直接配置 |
c.signingConfigs
属性名 | 含义 |
---|---|
storeFile | 签名证书文件 |
storePassword | 签名证书文件的密码 |
storeType | 签名证书的类型 |
keyAlias | 签名证书中密钥别名 |
keyPassword | 签名证书中该密钥的密码 |
android {
signingConfigs {
release{
storeFile file('myFile.keystore')
storePassword 'psw'
keyAlias 'myKey'
keyPassword 'psw'
}
}
}
复制代码
d.productFlavors
属性名 | 含义 |
---|---|
applicationId | 设置该渠道的包名 |
consumerProguardFiles | 对aar包进行混淆 |
manifestPlaceholders | |
multiDexEnabled | 启用多个dex的配置,可突破65535方法问题 |
proguardFiles | 混淆使用的文件配置 |
signingConfig | 签名配置 |
testApplicationId | 适配测试包的包名 |
testFunctionalTest | 是不是功能测试 |
testHandleProfiling | 是否启用分析功能 |
testInstrumentationRunner | 配置运行测试使用的Instrumentation Runner的类名 |
testInstrumentationRunnerArguments | 配置Instrumentation Runner使用的参数 |
useJack | 标记是否启用Jack和Jill这个全新的、高性能的编译器 |
dimension | 维度,经过flavorDimensions方法声明,声明先后表明优先级 |
//定义baidu和google两个渠道,并声明两个维度,优先级为abi>version>defaultConfig
android{
flavorDimensions "abi", "version"
productFlavors{
google{
dimension "abi"
}
baidu{
dimension "version"
}
}
复制代码
e.buildConfigFiled
buildConfigField(String type,String name,String value)
android{
buildTypes{
debug{
buildConfigField "boolean", "LOG_DEBUG", "true"
buildConfigField "String", "URL", ' "http://www.ecjtu.jx.cn/" '
}
}
}
复制代码
6.多项目构建
和Java Grdle多项目构建同样的,经过settings.gradle
配置管理多项目;在每一个项目都有一个build.gradle
,采用项目依赖就能实现多项目协做。
项目直接依赖通常适用于关联较紧密、不可复用的项目,若是想让项目被其余项目所复用,好比公共组件库、工具库等,能够单独发布出去。
7.多渠道构建
a.基本原理
Build Type有release、debug两种构建类型 Product Flavor有baidu、google两种构建渠道 Build Variant有baiduRelease、baiduDebug、googleRelease、googleDebug四种构件产出
构建渠道(Product Flavor)还能够经过dimension进一步细化分组
assemble开头的负责生成构件产物(Apk)
assembleBaidu:运行后会生成baidu渠道的release和debug包 assembleRelease:运行后会生成全部渠道的release包 assembleBaiduRelease:运行后只会生成baidu的release包
b.构建方式:经过占位符manifestPlaceholders
实现:
//AndroidManifest
<meta-data
android: value="Channel ID"
android:name="UMENG_ CHANNEL"/>
//build.gradle
android{
productFlavors{
google{
manifestPlaceholders.put("UMENG_ CHANNEL", "google")
}
baidu{
manifestPlaceholders.put("UMENG_ CHANEL", "baidu")
}
}
复制代码
//改进:经过productFlavors批量修改
android{
productFlavors{
google{
}
baidu{
}
ProductFlavors.all{ flavor->
manifestPlaceholders.put("UMENG_ CHANEL", name)
}
}
复制代码
8.高级应用
a. 使用共享库
<uses-library>
指定//声明须要使用maps共享库,true表示若是手机系统不知足将不能安装该应用
<uses-library
android:name="com.google.android.maps"
android:required="true"
/>
复制代码
b. 批量修改生成的apk文件名
applicationVariants
:仅仅适用于Android应用Gradle插件libraryVariants
:仅仅适用于Android库Gradle插件testVariants
:以上两种Gradle插件都使用
applicationVariants
是一个DomainObjectCollection集合,经过all方法遍历每个ApplicationVariant,这里有googleRelease和googleDebug两个变体;而后判断名字是否以.apk结尾,若是是就修改其文件名。示例中共有。
c.动态生成版本信息
defaultConfig
中的versionName
指定ext{}
括起来,经过apply from将其引入到build.gradle,版本信息就被看成扩展属性直接使用了d.隐藏签名文件信息
signingConfigs {
if (System.env.KEYSTORE_PATH != null) {
//打包服务器走这个逻辑
storeFile file(System.env.KEYSTORE_PATH)
keyAlias System.env.ALIAS
keyPassword System.env.KEYPASS
storePassword System.env.STOREPASS
} else {
//当不能从环境变量取到签名信息时,使用本地debug签名
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
复制代码
e.动态添加自定义的资源
productFlavors{
google{
resValue 'string', 'channel_tips', 'google渠道欢迎你'
}
}
复制代码
以google为例,在debug模式下,资源文件保存目录:build/generated/res/resValues/google/debug/values/generated.xml
f.Java编译选项
经过compileOptions{}
闭包进行编译配置,可配置项:
android{
compileOptions{
encoding = 'utf-8'
sourceCompatibility = JavaVersion.VERSI0N_ 1_ 6
targetCompatibility = JavaVersion.VERSION_ 1_ 6
}
}
复制代码
g. adb选项配置
经过adbOptions{}
闭包进行adb配置,可配置项:
android{
adbOptions{
timeOutInMs = 5*1000
installOptions '-r', '-s'
}
}
复制代码
h.DEX选项配置
经过dexOptions {}
闭包进行dex配置,可配置项: