标签:
Gradle是一个基于Java(JVM)平台的构建体系(build system),它的一些特性:
讲一个概念closure(闭包),此处不讲Groovy的语法,深入学习Groovy
closure是被包装成对象的一段代码块,它可以像方法那样传入参数并返回一个值;
表现形式如下:
{ [closureParameters -> ] statements }
1、简单声明
// Groovy object iteration
list.each { item -> /* do something with item */ }
2、利用赋值声明
def printer = { line -> println line }
3、应用方法作为closure
//利用reference.&操作符
class SizeFilter {
Integer limit
boolean sizeUpTo(String value) {
return value.size() <= limit
}
}
SizeFilter filter6 = new SizeFilter(limit:6)
Closure sizeUpTo6 = filter6.&sizeUpTo
def adder = { x, y -> return x+y }
assert adder(4, 3) == 7
assert adder.call(2, 6) == 8
//在Groovy构建脚本中,方法调用可以写成如下形式
method argOne, keyOne: valueOne, argTwo, keyTwo: valueTwo, argThree
//Groovy‘s runtime将解释为:
method([keyOne: valueOne, keyTwo: valueTwo], argOne, argTwo, argThree)
//最终将会调用有如下签名的方法
def method(Map m, argOne, argTwo, argThree)
/**
*方法void buildscript(Closure configureClosure)将
*closure作为参
*/
buildscript {
repositories {
jcenter()
}
dependencies {
/**
*方法Dependency add(String configurationName,
*Object dependencyNotation)接受参数
*/
classpath ‘com.android.tools.build:gradle:2.1.0‘
}
}
Groovy脚本会被编译成类。举例如下:
相对于传统的Java类,一个包含main方法的Groovy类可以如下书写:
class Main {
static void main(String... args) {
println ‘Groovy world!‘
}
}
和Java一样,程序会从这个类的main方法开始执行,这是Groovy代码的一种写法,实际上执行Groovy代码完全可以不需要类或main方法,所以更简单的写法如下:
println ‘Groovy world!‘
上面这两中写法其实是一样的,具体我们可以通过如下命令进行编译为class文件:
import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
def run() {
println ‘Groovy world!‘
}
static void main(String[] args) {
InvokerHelper.runScript(Main, args)
}
}
可以看见,上面我们写的groovy文件编译后的class其实是Java类,该类从Script类派生而来(查阅API);可以发现,每个脚本都会生成一个static main方法,我们执行groovy脚本的实质其实是执行的这个Java类的main方法,脚本源码里所有代码都被放到了run方法中,脚本中定义的方法(该例暂无)都会被定义在Main类中。
Gradle脚本是配置脚本(configuration scripts),当脚本执行的时候会创建一个关联对象(delegate object of script)。比如说,构建脚本(build script)执行的时候,它会配置关联对象project。
Type of script | Delegates to instance of |
---|---|
Init script | Gradle |
Build script | Project |
Settings script | Settings |
构建初始化时创建,整个构建执行过程中只有这么一个对象,一般很少去修改这个默认配置脚本
每个settings.gradle会转换成一个Settings对象
在Gradle中每个build.gradle对应一个Project对象,每个Project在构建的时候都包含一系列Task。
在脚本中可以使用关联对象(project、Gradle、settings)的属性(properties)和方法(methods),因为Gradle脚本实现了接口Script,所以接口Script的属性和方法也可以在脚本中使用
所谓的我们编写Gradle脚本,实质大多数时候都是在编写构建脚本Build script,所以说 Project和Script对象的属性和方法等API非常重要
。
所有的Gradle脚本都会实现Script接口,编译后的Script类会实现这个接口,接口Script的properties和methods可以在Gradle脚本中使用;
通常会有一个关联对象与Script对象关联;举例来说,一个构建脚本会将Project对象与它关联,一个初始化脚本会将Gradle对象与它关联,任何properties或者方法在Script对象中找不到,就需要去它的关联对象中去找。
生命周期(lifecycle)
一个project在构建时都具备如下流程:
创建一个Settings实例。
评估settings.gradle脚本,通过该文件配置刚才创建的Settings实例。
通过创建好的Settings实例创建Project实例的层级结构。
最后通过上面创建的Project实例去执行每个Project对应的build.gradle脚本。
Tasks
project是一个task的集合,每一个task完成一份基本的工作(比如说编译类,进行单元测试)
dependencies
project为完成工作需要建立多个依赖关系,dependencyHandler用来管理dependencies;
这些依赖关系可以存在于configurations和从repositories中获取。
plugins
插件可以用来模块化和复用project configuration,通过PluginAware.apply()来运用plugin;
properties和methods
在脚本中可以使用接口project的任何方法和属性
Gradle支持单一或多个projects,在初始化的时候,Gradle决定哪些projects参与构建,并为每一个project创建一个Project实例;实质为执行settings.gradle.
在这个时期,Project对象完成配置,将整个build的Project和task的关系确定,建立有向图来确定task间的依赖关系,实质为解析所有参与构建的projects的build.gradle;
Gradle开始执行选定的tasks及其依赖tasks,完成目标的构建;
构建脚本是由语句、代码块组成。
语句包括方法调用、属性赋值、变量定义;
代码块是调用以闭包(closure)为参数的方法;在执行的时候,闭包参数会配置相应的关联对象
Android Plugin for Gradle, Revision 2.1.0
Gradle和Android插件独立于Android Studio运行,也就是说在没有Android studio的情况下你也能构建你的Android App。Android构建体系让你能够自定义构建配置,而不用修改app的源码文件。
典型的构建过程如图所示:
新建一个工程,Android Studio会自动创建一些文件,如下图
位于project的根目录下,所有模块(整个project)的构建文件
/**
*buildscript {} 为Gradle配置仓库和依赖,例如将Android插件添加为依赖,
*modules自己的依赖不在这里配置。
*/
buildscript {
/**
*repositories {}配置repositories,Gradle用它来搜索或者下载依赖。
*Gradle支持远程仓库(JCenter,Maven Central和Ivy),你也可以用本地的
*仓库,代码中定义了JCenter作为仓库,Gradle需要用它来查找依赖。
*/
repositories {
jcenter()
}
dependencies {
/**
*dependencies {}配置依赖,Gradle用它来构建project,下面的代码将
*2.1.0版Android插件作为路径依赖。
*/
classpath ‘com.android.tools.build:gradle:2.1.0‘
}
}
/**
*allprojects {}配置project中所有modules的repositories
*和dependencies(例如第三方插件和库函数);
*单个模块自己的依赖不能在这里配置,而是在module-level的build.gradle文件
*中配置;
*下面的代码将JCenter和mavenCentral作为仓库。
*/
allprojects {
repositories {
jcenter()
mavenCentral()
}
}
module-level build.gradle文件,配置module的构建。
/**
*第一行配置Android插件运用于构建,使得android {}可用于Android-specific的
*构建选项
*/
apply plugin: ‘com.android.application‘
/**
*android {} 是配置Android-specific构建选项的地方
*/
android {
/**
* compileSdkVersion规定了Gradle编译使用的Android API版本
* 即你可以使用比他低的API版本
* buildToolsVersion规定了SDK build tools的版本
* /
compileSdkVersion 21
buildToolsVersion "21.1.2"
/**
*defaultConfig {}包含了所有构建版本的默认设置和条目,在动态构建的过程中
*可以override掉main/AndroidManifest.xml一些属性
*/
defaultConfig {
/**
* applicationId唯一的标识发布的package
* /
applicationId "io.rong.app"
//app要求的最低的API版本
minSdkVersion 9
//测试app时使用的API版本
targetSdkVersion 19
//版本号
versionCode 1
//版本的名字
versionName "2.4.10 Dev"
}
//配制project的结构
sourceSets {
main {
jni.srcDirs = []
jniLibs.srcDirs = [‘src/main/libs‘]
}
}
signingConfigs {
config {
storeFile file("rong.key")
storePassword "Amigo123"
keyAlias "RongCloud"
keyPassword "Amigo123"
}
}
/**
*buildTypes {}配置多个构建类型,默认的,构建体系定义了debug和release的
*构建类型,构建类型设置Proguard是否可用
*/
buildTypes {
release {
/**
*默认的,Android Studio在release构建类型中使用Proguard
*设置minifyEnabled为true
*/
minifyEnabled true
//签名的配置
signingConfig signingConfigs.config
//从Android SDK中运用默认的ProGuard的设置
proguardFiles getDefaultProguardFile(‘proguard-android-optimize.txt‘),‘proguard-rules.pro‘
}
debug {
minifyEnabled false
shrinkResources false
/**
*将debug的构建类型的报名设为<app appliationId>.debug,
*这样能够同时安装debug和release版的APK到相同的Android设备中
*/
applicationIdSuffix ".debug"
}
}
/**
*productFlavors {}配置多个project flavors
*它允许你创建不同版本的app,它可以override defaultConfig {} 中的设置
*Product flavors是可选的设置,默认不配置
*下面创建了免费和付费的product flavor,每一个product flavor会定义自己的
*application ID,这样它们可以同时安装或者发布
*/
productFlavors {
free {
applicationId ‘com.example.myapp.free‘
}
paid {
applicationId ‘com.example.myapp.paid‘
}
}
/**
*lint工具的配置选项,Lint工具检查Android project的源文件中潜在
*的bugs、改善优化correctness
*/
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
}
//配置当前模块的依赖
dependencies {
//告诉Gradle将所有JAR文件添加到app/libs folder
compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
compile ‘com.android.support:appcompat-v7:19.1.0‘
compile ‘com.android.support:support-annotations:21.0.2‘
compile project(‘:kit‘)
compile files(‘libs/TencentSearch1.1.2.16095.jar‘)
compile files(‘libs/TencentMapSDK_Raster_v1.1.2.16281.jar‘)
}
配置project-wide的Gradle设置
配置构建系统的本地环境,例如SDK的安装路径,它是Android Studio自动生成的,不要手动修改。
gradle.settings文件告诉Gradle哪些modules需要参与构建app。
//这个文件引用了工程所有的模块
include ‘:app‘, ‘:lib‘, ‘:kit‘,‘thirdparty‘,‘:push‘,‘:toollib‘
构建自定义配置要求改变build.gradle文件,而这些文本文件使用DSL来描述和操作构建逻辑
,使用的脚本语言是Groovy,而你不需要掌握Groovy,你只需要掌握Android插件提供的DSL元素。
构建类型定义了Gradle构建和打包app的特定properties;
默认的情况下,Android插件自动构建debug和release版的app;
debug构建类型用debug key来签名APK;而release的构建类型使用release key来进行发布;
你可以自定义其他类型的Build type;
android {
...
defaultConfig {...}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
}
debug {
applicationIdSuffix ".debug"
}
/**
* ‘initWith‘属性允许你复用其他构建类型的配置,你只需要修改你想改变的
* 配置,下面的例子中‘jnidebug’就使用了debug的build type,只是改变了
* applicationIdSuffix和versionNameSuffix的设置
*/
jnidebug {
/**
* This copies the debuggable attribute and debug signing
* configurations.
* /
initWith debug
applicationIdSuffix ".jnidebug"
jniDebuggable true
}
}
}
除了修改build的properties外,build types也可以添加特殊的sourceSet和resource。比如说每一个build type,其sourceSet被创建了,它的默认位置在src//,比如src/debug/java目录将被添加到debug版的APK
Product flavors代表你要发布的不同版本,比如说免费和付费的版本,你可以添加sourceSet来增加一些特殊的属性;一个project可以有不同的flavors来构建不同的应用
android {
...
defaultConfig {...}
buildTypes {...}
productFlavors {
demo {
applicationId "com.example.myapp.demo"
versionName "1.0-demo"
}
full {
applicationId "com.example.myapp.full"
versionName "1.0-full"
}
}
}
Build Type + Product Flavor = Build Variant
默认的,Android Studio创建的main/ source set包含了所有build variants所共有的部分,然而build types和product flavors可以创建新的source set来控制Gradle编译和打包过程。举例来说,你可以在main/ sourceset中实现基本的功能,而用product flavor的sourceset来改变不同客户端的应用名以及debug build type的build variants的一些特殊的权限和日志功能。
build type,product flavor的sourceSet的结构与main/ sourceSet一样,除了根目录的名字是build type,product flavor的名字;举例来说,你在debug build type的sourceSet中创建manifest.xml文件:
MyProject/
app/
src/
main/
debug/
java/
res/
// This manifest is only used with build variants that use
// the debug build type.
AndroidManifest.xml
Gradle根据build types和product flavors自动创建build variants,并且按照方式命名。例如,如果你创建了‘demo’和‘full’的product flavors,结合默认的‘debug’和‘release’构建类型,Gradle创建了下面的build variants:
demoDebug
demoRelease
fullDebug
fullRelease
你在构建demoDebug的build variant时,Gradle会找到这些目录,并且优先级从高到低:
src/demoDebug/ (build variant source set)
src/debug/ (build type source set)
src/demo/ (product flavor source set)
src/main/ (main source set)
这样做的原因是:demoDebug/ sourceSet中可能有build variant一些特殊的设置,demoDebug/和debug/中有相同的文件时,优先使用demoDebug/ sourceSet中的文件.
在构建过程中构建规则是:
下面的例子展示了app/ module’s build.gradle三种不同类型的依赖
android {...}
...
dependencies {
// The ‘compile‘ configuration tells Gradle to add the dependency to the
// compilation classpath and include it in the final package.
// Dependency on the "lib" module from this project
compile project(":lib")
// Remote binary dependency
compile ‘com.android.support:appcompat-v7:19.0.1‘
// Local binary dependency
compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
}
/**
*将本地的Android library module添加为依赖,要求
*构建系统在构建app时将这个module包含进来并编译。
*/
compile project(":lib")
/**
*通过JCenter的协助将22.0.1版的Android support library
*添加为依赖,默认的,Android Studio在top-level的构建文件
*中使用JCenter仓库来配置projects,在你同步projects时Gradle
*会自动从JCenter中拉取dependency
*/
compile ‘com.android.support:appcompat-v7:22.0.1‘
/**
*告诉构建体系将app/libs/目录下的JAR文件添加到
*app的包中,如果你的module建立本地的binary
*dependencies,将此JAR文件复制到<moduleName>/libs中。
*/
compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
Gradle需要明确地为release build’s APK签名,请阅读用Android Studio签名release build type
debug mode:
开发时使用,Android SDK工具自动生成,证书(certificate)有一个private key和已知的password,每次app的改变和调试不需要输入password;
当你在Android Studio中运行或者调试project时自动以debug mode运行的
debug的配置使用debug keystore,位置在$HOME/.android/debug.keystore,debug build type默认使用这个。
release mode:
发布app时使用,使用自己的certificate:
...
android {
...
defaultConfig {...}
signingConfigs {
release {
storeFile file("myreleasekey.keystore")
storePassword "password"
keyAlias "MyReleaseKey"
keyPassword "password"
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
}
}
}
Signing Your App in Android Studio
用来精简代码和resources,ProGuard可检测和移除无用的classes,fields,methods和属性;你可以自定义ProGuard规则,默认的该文件放在module的根目录下。
android {
buildTypes {
release {
//使得ProGuard可用
minifyEnabled true
/**
*getDefaultProguardFile(‘proguard-android.txt‘)从
*Android SDK tools/proguard/文件中获取ProGuard的设置
*proguard-rules.pro文件为自定义的的ProGuard文件,默认放在
*module的根目录下
*/
proguardFiles getDefaultProguardFile(‘proguard-android.txt‘),
‘proguard-rules.pro‘
}
}
...
}
Lint工具检查Android project的源文件中潜在的bugs、改善优化correctness、security、performance、usability、accessiblility。
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‘
}
}
构建文件中的插件会自动创建出一系列的任务,通常会有以下四种:
* assemble:负责project输出的task
* check:运行所有检查(checks)的task
* build:执行assemble和check的task
* clean:清除project输出的task
assemble、check、build task只是起到了’anchor’ tasks的作用,实际上不做任何事,添加与之关联的task来执行具体的任务。
这样做的原因是不管是什么样project、用什么样插件,只要执行assemble、check、build task,那么与之关联的task都会执行。
Library project和常规的Android project相似,但不同的地方在于Library project使用了不同的插件。
apply plugin: ‘com.android.library‘
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
}
...
Library project的主要输出是一个.arr包(代表着Android archive),它包含编译代码(a jar and/or native.so文件)和资源文件 (manifest, res, assets)。
dependencies {
compile project(‘:libraries:lib1‘)
compile project(‘:libraries:lib2‘)
}
标签:
原文地址:http://blog.csdn.net/carryoner/article/details/51548395