深入浅出Gradle 整理

转载至 http://blog.csdn.net/lzyzsd/article/details/42131637


深入浅出Android Gradle构建系统(一:简介)

gradle是Android开发中引入的全新的构建系统,因为全新的构建系统主要是出于下面的目的:

1. 方便复用代码和资源
2. 构建多种版本的apk更见简单,不论是为多渠道构建不同的apk还是构建不同环境的apk(debug,release)
3. 方便配置,扩展,自定义构建过程

4. 良好的IDE集成

为什么选择Gradle?

Gradle主要有以下几个有点:

1. 使用领域驱动语言(DSL)来描述构建逻辑
2. 构建脚本使用Groovy,可以方便的定制构建逻辑
3. 内建的依赖管理系统,使用Maven或者Ivy
4. 非常灵活。可以使用最佳实践但并不强制
5. 良好的IDE支持

Gradle项目使用项目根目录下的build.gradle文件来配置

一个最简单的Java项目的build.gradle如下

[plain]  view plain copy
  1. apply plugin: 'java'  
这表示改项目会使用Gradle的java插件,该插件是Gradle默认提供的,java插件提供了构建java应用和运行测试的功能。

最简单的Android项目build.gralde
[plain]  view plain copy
  1. buildscript {  
  2.     repositories {  
  3.         mavenCentral()  
  4.     }  
  5.   
  6.   
  7.     dependencies {  
  8.         classpath 'com.android.tools.build:gradle:0.11.1'  
  9.     }  
  10. }  
  11.   
  12.   
  13. apply plugin: 'android'  
  14.   
  15.   
  16. android {  
  17.     compileSdkVersion 19  
  18.     buildToolsVersion "19.0.0"  
  19. }  
该Android构建文件包含3个部分:
buildscript { ... } 配置驱动构建过程的代码,意思就是buildscript中的配置仅仅在构建过程中起作用,也就是构建程序所使用的配置。
上面的代码中就声明了我们的构建程序会使用Maven中央仓库,并且有一个classpath依赖是指向一个Maven库的。这个Maven库就是Android Gradle插件,版本号是0.11.1。

随后就是使用这个Android插件,和之前使用Java插件一样。

最后,android { ... }配置了Android项目构建时需要的所有参数。
默认情况下,只需要指定compileSdkVersion和buildtoolsVersion,compileSdkVersion指定使用哪个版本的sdk编译,buildToolsVersion指定使用哪个版本的构建工具。


注意点:
1. 只需要使用android插件,再使用Java插件会报错.
2. 在local.properties中使用sdk.dir属性指定SDK路径,或者你可以使用ANDROID_HOME环境变量。

深入浅出Android Gradle构建系统(二:项目结构)

这篇主要介绍使用Gradle的Android项目的目录结构,以及在Gradle中的配置


Gradle采用约定优于配置的原则,最简单方式是使用一个默认的目录结构。当然目录结构是可以自己修改的。

默认情况下,android gradle项目的代码都在src目录下,src下会有两个目录main和androidTest,其中main目录下是项目代码,androidTest目录下是测试代码。
src/main/
src/androidTest/

在main和androidTest目录下面,针对不同类型的code,又不会不同的目录。
对于Java和Android的Gradle插件,Java代码和Java资源分别对应了java目录和resources目录。Android插件还需要一些其他的目录和文件,比如
AndroidManifest.xml
res/
assets/
aidl/
rs/
jni/


下面我们来看一下如何更改这些默认的配置。

Android工程,默认情况下,java文件和resource文件分别在src/main/java和src/main/res目录下,在build.gradle文件,andorid{}里面添加下面的代码,便可以将java文件和resource文件放到src/java和src/resources目录下。(注意,如果你在gradle文件中修改了,只需要重新sync一下,gradle会自动创建新的目录,并将对应的文件移动到新的目录下)
[java]  view plain copy
  1. sourceSets {  
  2.     main {  
  3.         java {  
  4.             srcDir 'src/java'  
  5.         }  
  6.         resources {  
  7.             srcDir 'src/resources'  
  8.         }  
  9.     }  
  10. }  

更简便的写法是
[java]  view plain copy
  1. sourceSets {  
  2.     main.java.srcDirs = ['src/java']  
  3.     main.resources.srcDirs = ['src/resources']  
  4. }  
数组里其实是可以指定多个目录,这样就可以将代码和资源放置到多个目录下。
在看一个Android项目的例子:
[java]  view plain copy
  1. android {  
  2.     sourceSets {  
  3.         main {  
  4.             manifest.srcFile 'AndroidManifest.xml'  
  5.             java.srcDirs = ['src']  
  6.             resources.srcDirs = ['src']  
  7.             aidl.srcDirs = ['src']  
  8.             renderscript.srcDirs = ['src']  
  9.             res.srcDirs = ['res']  
  10.             assets.srcDirs = ['assets']  
  11.         }  
  12.   
  13.   
  14.         androidTest.setRoot('tests')  
  15.     }  
  16. }  

这里的main code其实使用的就是Android Gradle的默认值,而androidTest不再使用默认的androidTest目录,而是使用tests目录。


深入浅出Android Gradle构建系统(三:build task)

构建任务(Build Tasks)

java和Android通用的任务
在build文件中使用了Android或者Java插件之后就会自动创建一系列可以运行的任务。

Gradle中有如下一下默认约定的任务:
1. assemble
该任务包含了项目中的所有打包相关的任务,比如java项目中打的jar包,Android项目中打的apk
2. check
该任务包含了项目中所有验证相关的任务,比如运行测试的任务
3. build
该任务包含了assemble和check
4. clean
该任务会清空项目的所有的输出,删除所有在assemble任务中打的包

assemble, check 和 build 任务实际上并不做任何事情,它们其实只是为插件提供了一个钩子,真正的事情都是由插件来完成的。

这样的话,开发人员就不需要关心我到底运行的是一个java项目还是一个Android项目,也不用关心我到底使用了哪些gradle插件,因为我都可以调用这些约定的任务来完成构建。

比如使用findbugs插件会创建一个新的任务,并且使得check任务依赖于这个新建的任务,这样每次执行check任务的时候,都会执行这个新建的任务。

在命令行执行
[java]  view plain copy
  1. gradle tasks  
[javascript]  view plain copy
  1. </pre>会列出所有主要的任务如果想看到全部的任务和它们的依赖,可以运行:<pre name="code" class="java">gradle tasks --all  

注意:Gradle会自动检查一个任务的输入和输出。比如连续两次运行build任务的,Gradle会报告所有的任务都已经是最新刚运行过的了,不需要再次运行。这样的话,任务之间就算是有相互依赖,也不会导致重复的执行。

Java项目常用的任务

Java plugin 主要创建了两个任务:
1. jar
assemble任务会依赖jar任务,看名字就知道这是负责打jar包的任务。jar任务本身又会依赖很多其他的任务,比如classes任务,classes任务会编译java代码
2. test
check任务会依赖test任务,这个任务会运行所有的测试。测试代码使用testClasses任务编译,但是我们基本不用手动运行testClasses任务因为test任务已经添加了对它的依赖。

通常情况下,我们只要运行assemble和check任务就够了。
想查看java插件提供的所有任务以及他们的依赖可以点这个[链接](http://gradle.org/docs/current/userguide/java_plugin.html)

Android项目常用的任务

和其他gradle插件一样,Android插件也提供了一些默认的任务,比如assemble,check,build,clean,同时它也提供了一些自己特有的任务,比如:
1. connectedCheck
运行那些需要在真机或者模拟器上执行的检查任务,这些任务会并行地在所有连接的设备上运行
2. deviceCheck
使用APIs连接远程设备执行检查.主要用于CI(持续集成)服务上.
上面两个任务都会执行 assemble 和 check任务。新加这两个任务是很有必要的,这样可以保证我们可以运行那些不需要连接设备的检查任务。

注意:build任务并不依赖于deviceCheck或者connectedCheck

一个Android项目通常至少会有两种输出:debug apk和release apk。对应的gradle中有两个任务可以分别输出不同的apk:
assembleDebug
assembleRelease
这两个任务又会依赖其他的任务来构建一个apk。assemble任务依赖这两个任务,调用assemble任务就会生成两种apk。

小提示: Gradle支持在命令行使用camel风格的缩写来代替任务的名字,比如:
[java]  view plain copy
  1. gradle aR  
等同于
[java]  view plain copy
  1. gradle assembleRelease  
只要没有其他任务的缩写也是'aR'

check相关的任务的依赖:
check依赖lint
connectedCheck依赖 connectedAndroidTest和connectedUiAutomatorTest (还没有实现)
deviceCheck依赖于那些实现了test扩展的插件所提供的任务

最后,Android gradle插件还提供了install和uninstall任务,用来安装和卸载apk

深入浅出Android Gradle构建系统 (四:自定义构建过程之配置manifest)


Android Gradle插件提供了大量的DSL来自定义构建过程,这篇blog就来讲解如何在gradle中配置manifest。


DSL提供了配置以下Manifest条目的功能:
minSdkVersion
targetSdkVersion
versionCode
versionName
applicationId (更加方便有效的包名 -- [参考](http://tools.android.com/tech-docs/new-build-system/applicationid-vs-packagename))
测试app的包名

Instrumentation test runner


示例:
[java]  view plain copy
  1. android {  
  2.     compileSdkVersion 19  
  3.     buildToolsVersion "19.0.0"  
  4.   
  5.   
  6.     defaultConfig {  
  7.         versionCode 12  
  8.         versionName "2.0"  
  9.         minSdkVersion 16  
  10.         targetSdkVersion 16  
  11.     }  
  12. }  

android元素中的defaultConfig元素就是我们用来配置Manifest的地方。早期版本的Android插件使用packageName来配置manifest中的packageName属性,从0.11.0开始,使用applicationId来代替packageName。这样可以消除应用的包名(其实就是应用的id)和java的包名之间的混淆。


更强大的是build文件中描述的配置可以是动态的,比如可以从文件或者自定义的逻辑中获取版本名称。
[java]  view plain copy
  1. def computeVersionName() {  
  2.     ...  
  3. }  
  4.   
  5.   
  6. android {  
  7.     compileSdkVersion 19  
  8.     buildToolsVersion "19.0.0"  
  9.   
  10.   
  11.     defaultConfig {  
  12.         versionCode 12  
  13.         versionName computeVersionName()  
  14.         minSdkVersion 16  
  15.         targetSdkVersion 16  
  16.     }  
  17. }  

注意:不要使用作用域中的getter方法名作为函数名,比如在defaultConfig{}作用域中调用getVersionName()将会自动调用defaultConfig.getVersionName(),而不会调用自定义的方法。
如果某个属性的值没有使用DSL设置,这个属性将会使用某些默认值,下表展示了默认值的处理过程。


 属性名    DSL对象中的默认值   默认值
 
 Property Name Default value in DSL object Default value
 versionCode -1 value from manifest if present
 versionName null value from manifest if present
 minSdkVersion -1 value from manifest if present
 targetSdkVersion -1 value from manifest if present
 applicationId null value from manifest if present
 testApplicationId null applicationId + “.test”
 testInstrumentationRunner null android.test.InstrumentationTestRunner
 signingConfig null null
 proguardFile N/A (set only) N/A (set only)
 proguardFiles N/A (set only) N/A (set only) 

如果你想在build脚本中使用自定义的逻辑来查询这些属性,第二列中的值就很重要。比如,你可以编写如下的代码:
[java]  view plain copy
  1. if (android.defaultConfig.testInstrumentationRunner == null) {  
  2.     // assign a better default...  
  3. }  
如果属性的值仍然是null,那么在构建的时候,就会使用第三列的默认值,但是DSL元素中并不包含这些默认值,因此你不能在程序中查询这些值。这样做的目的是仅在必要的时候(构建时)才会去解析manifest内容。

android-gradle-深入浅出-五:build type

默认情况下,Android插件自动为项目构建一个debug和一个release版本的应用。这两个版本的不同主要体现在在非开发机上的调试功能以及APK的签名方式。debug版本使用一个用公开的name/password创建的key来签名(这样构建的时候就不需要提示输入密码了)。release版本在构建的时候不会进行签名,而是稍后在做。
这个可以使用gradle中的BuildType对象来进行配置。默认情况下,2个BuildType的实例会被创建,一个debug,一个release。Android插件允许自定义这两个实例,当然你也可以创建其他的build type。配置由buildTypes这个DSL来完成:
[java]  view plain copy
  1. android {  
  2.     buildTypes {  
  3.         debug {  
  4.             applicationIdSuffix ".debug"  
  5.         }  
  6.   
  7.   
  8.         jnidebug.initWith(buildTypes.debug)  
  9.         jnidebug {  
  10.             packageNameSuffix ".jnidebug"  
  11.             jniDebuggable true  
  12.         }  
  13.     }  
  14. }  
上面的代码完成了下列配置:
1.配置默认的debug Build Type
  设置debug版本的报名为<应用id>.debug,这样就可以在设备上同时安装debug和release版本了。
2.创建一个新的BuildType,名字是jnidebug,同时配置它是复制自debug Build Type。
  配置jnidebug开启debug版本的JNI组件,添加一个不同的包名后缀。


创建一个新的的Build Types非常简单,只需要在buildTypes下面通过调用initWith或者使用闭包添加一个新的元素。下表是可以配置的属性以及默认值:


 属性明   debug版本默认值  release或其他版本 默认值
 debuggable  true  false
 jniDebuggable   false   false
 renderscriptDebuggable  false   false
 renderscriptOptimLevel  3   3
 applicationIdSuffix   null  null
 versionNameSuffix   null  null
 signingConfig   android.signingConfigs.debug  null
 zipAlignEnabled   false   true
 minifyEnabled   false   false
 proguardFile  N/A (set only)  N/A (set only)
 proguardFiles   N/A (set only)  N/A (set only)


出了这些属性,Build Types还可以用来配置代码和资源文件。针对每一个Build Type,一个新的对应的sourceSet会被创建,这个sourceSet使用一个默认的路径src/<buildtype名字>/。这就意味着Build Type的名字不能是main或者androidTest(这是由插件强制的),同时每个Build Type的名字必须是唯一的。


和其他的source sets一样,Build Type中的source set路径也是可以配置
[java]  view plain copy
  1. android {  
  2.     sourceSets.jnidebug.setRoot('foo/jnidebug')  
  3. }  

另外,对每一个Build Type,一个新的assemble<BuildType名字>任务会被创建.前面我已经讲过assembleDebug和assembleRelease任务了,这里就可解释这两个任务的来源了.当debug和release Build Types被预先创建的时候,他们对应的assemble任务也会被一起创建.


上面的build.gradle代码片段还会创建一个assembleJnidebug任务,assemble任务也会添加对assembleJniDebug任务的依赖,正如它对assembleDebug和assembleRelease任务的依赖一样。


小提示:你可以使用 gradle aJ命令来运行assembleJnidebug任务。


可能是使用场景:
仅在debug模式下使用的权限,release模式不使用。
debug时使用不同的实现
debug模式使用不同的资源(比如当一个资源的值依赖于签名的时候)


BuildType中的 代码/资源文件 将会被按照下列方式处理:
manifest配置会被merge到app manifest中
代码不会被merge,会被当做另一个代码目录(source folder)来使用
资源文件会覆盖同名的main中的资源文件

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值