随着 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'
}
}
}