随着Google
对Eclipse
的有情摈弃以及Studio
的一直壮大,Android
开发者逐步拜倒在Studio
的石榴裙下。
而作为Studio
的默认编译形式,Gradle
已逐步遍及。我最开始是被它的多渠道打包所吸引。接下来咱们就零碎的学习一下Gradle
。
简介
Gradle
是以Groovy
语言为根底,面向Java
利用为主。基于DSL(Domain Specific Language)
语法的自动化构建工具。
Gradle
汇合了Ant
的灵活性和弱小性能,同时也汇合了Maven
的依赖治理和约定,从而发明了一个更无效的构建形式。凭借Groovy
的DSL
和翻新打包形式,Gradle
提供了一个可申明的形式,并在正当默认值的根底上形容所有类型的构建。 Gradle
目前已被选作许多开源我的项目的构建零碎。
因为Gradle
是基于DSL
语法的,如果想看到build.gradle
文件中全副能够选项的配置,能够看这里
DSL Reference
根本的我的项目设置
一个Gradle
我的项目通过一个在我的项目根目录中的build.gradle
文件来形容它的构建。
简略的Build
文件
最简略的Android
利用中的build.gradle
都会蕴含以下几个配置:Project
根目录的build.gradle
:
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.5.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }}
Module
中的build.gradle
:
apply plugin: 'com.android.application'android { compileSdkVersion 23 buildToolsVersion "23.0.3" ...}
buildscript { ... }
配置了编译时的代码驱动. 这种状况下,它申明所应用的是jCenter
仓库。还有一个申明所依赖的在Maven
文件的门路。这里申明的蕴含了Android
插件所应用的1.5.0版本的Gradle
. 留神:这只会影响build
中运行的代码,不是我的项目中。我的项目中须要申明它本人所须要仓库和依赖关系。apply plugin : com.android.application
,申明应用com.androdi.application
插件。这是构建Android
利用所须要的插件。android{...}
配置了所有Android
构建时的参数。默认状况下,只有编译的指标版本以及编译工具的版本是须要的。
重要: 这里只能应用com.android.application
插件。如果应用java
插件将会报错。
目录构造
module/src/main
下的目录构造,因为有时候很多人把so
放到libs
目录就会报错:
- java/
- res/
- AndroidManifest.xml
- assets/
- aidl/
- jniLibs/
- jni/
- rs/
配置目录构造
如果我的项目的构造不规范的时候,可能就须要去配置它。Android
插件应用了类似的语法,然而因为它有本人的sourceSets
,所以要在android
代码块中进行配置。上面就是一个从Eclipse
的老我的项目构造中配置次要代码并且将androidTest
的sourceSet
设置给tests
目录的例子:
android { sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } androidTest.setRoot('tests') }}
就像有些人就是要把so
放到libs
目录中(这类人有点犟),那就须要这样进行批改。
留神:因为在旧的我的项目构造中所有的源文件(Java
,AIDL
和RenderScript
)都放到同一个目录中,咱们须要将sourceSet
中的这些新部件都设置给src
目录。
Build Tasks
对构建文件申明插件时通常或主动创立一些列的构建工作去执行。不论Java
插件还是Android
插件都是这样。Android
惯例的工作如下:
assemble
生成我的项目output
目录中的内容的工作。check
执行所有的查看的工作。build
执行assemble
和check
的工作。clean
清理我的项目output
目录的工作。
在Android
我的项目中至多会有两种output
输入:一个debug apk
和一个release apk
。他们都有本人的主工作来别离执行构建:
assemble
assembleDebug
assembleRelease
提醒:Gradle
反对通过命令行执行工作首字母缩写的形式。例如:
在没有其余工作合乎aR
的前提下,gradle aR
与gradle assembleRelease
是雷同的。
最初,构建插件创立了为所有build type(debug, release, test)
类型装置和卸载的工作,只有他们能被装置(须要签名)。
installDebug
installRelease
uninstallAll
uninstallDebug
uninstallRelease
uninstallDebugAndroidTest
根本的Build
定制
Android
插件提供了一些列的DSL
来让间接从构建零碎中做大部分的定制。
Manifest
整体局部
DSL
提供了很多重要的配置manifest
文件的参数,例如:
minSdkVersion
targetSdkVersion
versionCode
versionName
applicationId
testApplicationId
testInstrumentationRunnder
Android Plugin DSL Reference提供了一个残缺的构建参数列表。
把这些manifest
属性放到build
文件中的一个重要性能就是它能够被动静的设置。例如,能够通过读取一个文件或者其余逻辑来获取版本名称。
def computeVersionName() { ...}android { compileSdkVersion 23 buildToolsVersion "23.0.1" defaultConfig { versionCode 12 versionName computeVersionName() minSdkVersion 16 targetSdkVersion 23 }}
留神:不要应用可能与现有给定抵触的办法名。例如defaultConfig{...}
中应用getVersionName()
办法将会主动应用defaultConfig.getVersionName()
来带起自定义的办法。
Build Types
默认状况下Android
插件会主动将应用程序设置成有一个debug
版本和一个release
版本。
这就是通过调用BuildType
对象实现。默认状况下会创立两个实例,一个debug
实例和一个release
实例。Android
插件同样容许通过其余的Build Types
来定制其余的实例。这就是通过buildTypes
来设置的:
android { buildTypes { debug { applicationIdSuffix ".debug" } jnidebug { initWith(buildTypes.debug) applicationIdSuffix ".jnidebug" jniDebuggable true } }}
下面的代码执行了以下操作:
配置了默认
debug
的Build Type
:- 设置了它的
applicationId
。这样debug
模式就能与release
模式的apk
同时装置在同一手机上。
- 设置了它的
- 创立了一个新的
jnidebug
的Build Type
,并且把它设置为debug
的拷贝。 - 通过容许
JNI
组件的debug
和减少一个新的包名后缀来持续定制该Build Type
。
不论应用initWith()
还是应用其余的代码块,创立一个新的Build Types
都是非常简单的在buildTypes
代码块中创立一个新的元素就能够了。
签名配置
为利用签名须要应用如下几个局部:
A keystore
A keystore password
A key alias name
A key password
The store type
默认状况下有一个debug
的配置,设置了一个debug
的keystore
,有一个已知的明码。debug keystore
的地位是在$HOME/.android/debug.keystore
,如果没有的话他会被默认创立。Debug
的Build Type
会默认应用该debug
的签名设置。
当然也能够通过应用DSL
语法中的signingconfigs
局部来创立其余的配置来进行定制:
android { signingConfigs { debug { storeFile file("debug.keystore") } myConfig { storeFile file("other.keystore") storePassword "android" keyAlias "androiddebugkey" keyPassword "android" } } buildTypes { foo { signingConfig signingConfigs.myConfig } }}
下面的设置将把debug keystore
的地位改为我的项目的根目录。同样也创立了一个新的签名配置,并且有一个新的Build Type
应用它。
Dependencies, Android Libraries and Multi-project setup
Gradle
我的项目能够依赖其余的内部二进制包、或者其余的Gradle
我的项目。
本地包
想要配置依赖一个内部jar
包,须要在compile
的配置中增加一个dependency
。上面的配置是增加了所有在libs
目录的jar
包:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar'])}android { ...}
留神:DSL
元素中的dependencies
是Gradle API
中的规范元素。不属于andorid
元素。compile
配置是用来编译主利用的。它配置的所有局部都会被打包到apk
中。当然也有一些其余的配置:
compile
:main application
androidTestCompile
:test application
debugCompile
:debug Build Type
release Compile
:release Build Type
当然咱们能够应用compile
和<buildtype>.compile
这两种配置。创立一个新的Build Type
通常会主动基于它的名字创立一个新的配置局部。这样在像debug
版本而release
版本不实用的一些特地的library
时十分有用。
近程仓库
Gradle
只是应用Maven
和Ivy
仓库。然而仓库必须要增加到列表中,并且必须申明所依赖仓库的Maven
或者Ivy
定义。
repositories { jcenter()}dependencies { compile 'com.google.guava:guava:18.0'}android { ...}
留神:jcenter()
是指定仓库URL
的快捷设置。Gradle
反对近程和本地仓库。
留神:Gradle
会间接辨认所有的依赖关系。这就意味着如果一个依赖库本身又依赖别的库时,他们会被一起下下来。
本地AAR
库
dependencies { compile(name:'本地aar库的名字,不必加后缀', ext:'aar')}
多我的项目设置
Gradle
我的项目通常应用多我的项目设置来依赖其余的gradle
我的项目。例如:
MyProject/
- app/
libraries/
- lib1/
- lib2/
Gradle
会通过上面的名字来援用他们::app
:libraries:lib1
:libraries:lib2
每个我的项目都会有一个独自的build
文件,并且在我的项目的根目录还会有一个setting.gradle
文件:
MyProject/
- settings.gradle
app/
- build.gradle
libraries/
lib1/
- build.gradle
lib2/
- build.gradle
setting.gradle
文件中的内容非常简单。它指定了哪个目录是Gralde
我的项目:
include ':app', ':libraries:lib1', ':libraries:lib2'
:app
这个我的项目可能会依赖其余的libraries
,这样能够通过如下进行申明:
dependencies { compile project(':libraries:lib1')}
Library
我的项目
下面用到了:libraries:lib1
和:libraries:lib2
能够是Java
我的项目,:app
我的项目会应用他们俩的输入的jar
包。然而如果你须要应用android
资源等,这些libraries
就不能是一般的Java
我的项目了,他们必须是Android Library
我的项目。
创立一个Library
我的项目
Library
我的项目和一般的Android
我的项目的区别比拟少,因为libraries
的构建类型与应用程序的构建不同,所有它会应用一个别的构建插件。然而他们所应用的插件外部有很多雷同的代码,他们都是由com.android.tools.build.gradle
这个jar
包提供的。
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.1' }}apply plugin: 'com.android.library'android { compileSdkVersion 23 buildToolsVersion "23.0.1"}
一般我的项目与Library
我的项目的区别
Library
我的项目的次要输入我.aar
包。它联合了代码(例如jar
包或者本地.so
文件)和资源(manifest
,res
,assets
)。每个library
也能够独自设置Build Type
等来指定生成不同版本的aar
。
Lint Support
你能够通过指定对应的变量来设置lint
的运行。能够通过增加lintOptions
来进行配置:
android { lintOptions { // turn off checking the given issue id's disable 'TypographyFractions','TypographyQuotes' // turn on the given issue id's enable 'RtlHardcoded','RtlCompat', 'RtlEnabled' // check *only* the given issue id's check 'NewApi', 'InlinedApi' }}
Build
变量
构建零碎的一个指标就是能对同一个利用创立多个不同的版本。
Product flavors
一个product flavor
能够针对一个我的项目制订不同的构建版本。一个利用能够有多个不同的falvors
来扭转生成的利用。Product flavors
是通过DSL
语法中的productFlavors
来申明的:
android { .... productFlavors { flavor1 { ... } flavor2 { ... } }}
Build Type + Product Flavor = Build Variant
像咱们之前看到的,每个Build Type
都会生成一个apk
.Product Flavors
也是同样的:我的项目的输入僵尸所有Build Types
与Product Flavors
的联合。每种联合形式称之为Build Variant
。例如,如果有debug
和release
版本的Build Types
,下面的例子就会生成4种Build Variants
:
Flavor1
-debug
Flavor1
-release
Flavor2
-debug
Flavor2
-release
没有配置flavors
的我的项目依然有Build Variants
,它只是用了一个默认的flavor/config
,没有名字,这导致variants
的列表和Build Types
的列表比拟雷同。
Product Flavor
配置
android { ... defaultConfig { minSdkVersion 8 versionCode 10 } productFlavors { flavor1 { applicationId "com.example.flavor1" versionCode 20 } flavor2 { applicationId "com.example.flavor2" minSdkVersion 14 } }}
留神android.productFlavors.*
对象ProductFlavor
有android.defaultConfig
是雷同的类型。这就意味着他们有雷同的属性。defaultConfig
为所有的flavors
提供了一些根本的配置,每个flavor
都已重写他们。在下面的例子中,这些配置有:
flavor1
applicationId
:com.example.flavor1
minSdkVersion
: 8versionCode
: 20
flavor2
applicationId
:com.example.flavor2
minSdkVersion
: 14versionCode
: 10
通常,Build Type
配置会笼罩其余的配置。例如,Build Type
的applicationIdSuffix
会增加到Product Flavor
的applicationId
上。
最初,就像Build Types
一样,Product Flavors
也能够有他们本人的依赖关系。例如,如果有一个独自的flavors
会应用一些广告或者领取,那这个flavors
生成的apk
就会应用广告的依赖,而其余的flavors
就不须要应用。
dependencies { flavor1Compile "..."}
BuildConfig
在编译阶段,Android Studio
会生成一个叫做BuildConfig
的类,该类蕴含了编译时应用的一些变量的值。你能够观看这些值来扭转不同变量的行为:
private void javaCode() { if (BuildConfig.FLAVOR.equals("paidapp")) { doIt(); else { showOnlyInPaidAppDialog(); }}
上面是BuildConfig
中蕴含的一些值:
boolean DEBUG
-if the build is debuggable
int VERSION_CODE
String VERSION_NAME
String APPLICATION_ID
String BUILD_TYPE
-Build Type
的名字,例如release
String FLAVOR
-flavor
的名字,例如flavor1
ProGuard
配置
Android
插件默认会应用ProGuard
插件,并且如果Build Type
中应用ProGuard
的minifyEnabled
属性开启的话,会默认创立对应的task
。
android { buildTypes { release { minifyEnabled true proguardFile getDefaultProguardFile('proguard-android.txt') } } productFlavors { flavor1 { } flavor2 { proguardFile 'some-other-rules.txt' } }}
Tasks
管制
根本的Java
我的项目有一系列的tasks
一起制作输入文件。classes task
就是编译Java
源码的工作。 咱们能够在build.gradle
中通过应用classes
很简略的获取到它。就是project.tasks.classes
.
在Android
我的项目中,更多的编译task
,因为他们的名字通过Build Types
和Product Flavors
生成。
为了解决这个问题,android
对象有两种属性:
applicationVariants
-only for the app plugin
libraryVariants
-only for the library plugin
testVariants
-for both plugins
这些都会返回一个ApplicationVariant
,LibraryVariant
,TestVariant
的DomainObjectCollection
接口的实现类对象。DomainObjectCollection
提供了间接获取或者很不便的间接获取所有对象的办法。android.applicationVariants.all { variant -> ....}
设置编译语言版本
能够应用compileOptions
代码块来设置编译时应用的语言版本。默认是基于compileSdkVersion
的值。
android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_6 targetCompatibility JavaVersion.VERSION_1_6 }}
Resource Shrinking
Gradle
构建零碎反对资源清理:对构建的利用会主动移除无用的资源。不仅会移除我的项目中未应用的资源,而且还会移除我的项目所以来的类库中的资源。留神,资源清理只能在与代码清理联合应用(例如ProGuad
)。这就是为什么它能移除所依赖类库的无用资源。通常,类库中的所有资源都是应用的,只有类库中无用代码被移除后这些资源才会变成没有代码援用的无用资源。
android { ... buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}