1.Gradle是用来干什么的?
先上一个百科上的解释:
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。
接下来是通俗的理解:
软件开发讲究代码复用,通过复用可以使工程更易维护,代码量更少..... 开发者可以通过继承,组合,函数模块等实现不同程度上的代码复用.但不知你有没有想过,软件开发也是一种工程作业,绝不仅仅是写代码,还涉及到工程的各种管理(依赖,打包,部署,发布,各种渠道的差异管理.....),你每天都在build,clean,签名,打包,发布,有没有想过这种过程,也可以像代码一样被描述出来, 也可以被复用.
举个例子
国内有n个Android市场,n个手机品牌,n个手机尺寸......,一般公司都会针对不同的市场单独发包用来统计不同渠道的下载量等情况,可能需要针对不同(品牌,尺寸等各种硬件信息)的手机做一些特殊的处理,这个时候你可以针对不同的情况单独建一个工程,或者更好一点你可以通过一些变量来控制,像这样:
if(isMoto){do something} else if(isHuawei){do something} ...
差异管理
但这两种解决方法都有自己的缺点,特别是前一种有极大的代码重复.后一种稍微好一点,但这种方式的差异是运行时的,不是静态的,对于moto手机上的处理逻辑对华为手机来说一点作用也没有,但这一段针对moto手机的处理逻辑也被装到了华为手机上了,通过gradle的productFlavor与buildtype可以实现静态级的差异控制可以参考如何通过Gradle实现一套代码开发不同特性的APK · ByGhui
说到前面的多渠道问题,不同的渠道一般会对应不同的渠道号,你当然可以通过修改一次打一个包这种纯手工的方式来生成你的多渠道包,但据听说国内某团购网站的Android App有100多个渠道.这里出现了什么?重复,反复的去打包而且这些包之前的差异很小(只是渠道号不同),和写代码一样我们应该复用,通过Gradle可以实现一个命令打出所有的渠道包,一个命令打出指定的渠道包.再复杂一点,你可能需要不同的渠道对应不同的签名文件,不同的icon,不同的服务器地址...这些都可以通过Gradle来方便的实现.
依赖管理:
做软件开发你可能需要依赖各种不同的jar,library.你当然可以通过将.jar/library工程下载到本地再copy到你的工程中,但不知你是否听说过国外有个叫中央仓库的东西,在这个仓库里你可以找到所有你能想到以及你从来没听说过的jar,aar...The Central Repository Search Engine 这里可以找到所有你需要的依赖,而你需要的只是指定一个坐标,如下:
<img src="https://pic4.zhimg.com/8883d4b758b288a74eb4c104db854c5f_b.jpg" data-rawwidth="330" data-rawheight="24" class="content_image" width="330">剩下的依赖的寻找,下载,添加到classpath等你都不需要去关心,通过这种方式来维护依赖的好处有以下几点:
剩下的依赖的寻找,下载,添加到classpath等你都不需要去关心,通过这种方式来维护依赖的好处有以下几点:
- 依赖不会进入到你的版本控制仓库中(默认会缓存到~/.gradle/下)
- 方便卸载装载依赖(只是一条坐标依赖,不需要删除即可)
- 方便的版本管理,如上图中的2.3.3既是picasso的版本号,若改为+就表示从中央仓库中下载最新的版本
- 不同工程的相同依赖不会存在重复副本(只在~/.gradle下存在一份)
项目部署
这方面我没怎么接触过,但据我所知通过一些插件,可以实现自动将你的输出(.jar,.apk,.war...)上传到指定仓库,自动部署...
罗哩罗嗦说了这么多,不知大家有没有理解
总结一下:
- Gradle是一种构建工具,它可以帮你管理项目中的差异,依赖,编译,打包,部署......,你可以定义满足自己需要的构建逻辑,写入到build.gradle中供日后复用.
- Gradle不是一种编程语言,它不能帮你实现软件中的任何实际功能
以上部分是copy的其他文章,觉得文章讲的通俗易懂,链接http://www.cnblogs.com/1102whw/p/7602013.html
2.AndroidStudio中Gradle解析
(1)根目录下的builde.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
// Gradle中可以使用“//”或“/**/”来添加注释,与Java类似。
// 根目录下的build.gradle用于添加子工程或模块共用的配置项。
// "buildscript"的类型为script block,而且是最上层的script block,用于配置Gradle的Project实例。
//其API文档为https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:buildscript(groovy.lang.Closure)
// 其余的根script block有"allprojects", "dependencies", "configurations"等,更多的可见https://docs.gradle.org/current/dsl/的“Build script structure”一节。
// Script Block是一种method的调用,传入的参数为configuration closure。执行后会对Project的属性进行配置。
// 此处的"buildscript"用于配置Project的build script的classpath。
buildscript {
// 如果需要的话,从https://jcenter.bintray.com/下载code reposities。
repositories {
jcenter()
}
// 定义classpath,gradle会从“repositories”中下载对应版本的Gradle。如果使用gradle wrapper的话,感觉这个配置会被忽略。Wrapper会自己去下载所使用的gradle版本。
dependencies {
classpath 'com.android.tools.build:gradle:2.1.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
// 该配置会被应用到所有的子工程。
allprojects {
repositories {
jcenter()
}
}
// 运行gradle clean时,执行此处定义的task。
// 该任务继承自Delete,删除根目录中的build目录。
// 相当于执行Delete.delete(rootProject.buildDir)。
// gradle使用groovy语言,调用method时可以不用加()。
task clean(type: Delete) {
delete rootProject.buildDir
}
(2)根目录下的settings.gradle文件
// 调用include函数,将子工程app(目录名为app)导入进来。
// ':'表示app是一个相对路径,跟路径为该工程的根目录。
include ':app'
settings.gradle的作用就是导入子工程。它支持导入多个子工程,使整个工程支持multi-project的编译。
当有多个子工程时,gradle既可以在根目录下执行任务(比如:gradle tasks会显示在根目录下可以执行的任务),又可以在相应的子工程下执行任务(比如:gradle :app:tasks会显示在子工程app下可以执行的任务)。
如果有的app之间有依赖关系,或者app依赖需本地编译的库,使用multi-project编译会增加编译的灵活性,因为在build.gradle中可以指定或修改任务之间的依赖关系。
(3)Module中的build.gradle
apply plugin: 'com.android.application' //表示是一个应用程序的模块,可独立运行
//apply plugin: 'com.android.library' //表示是一个依赖库,不能独立运行
android {
//程序在编译的时候会检查lint,有任何错误提示会停止build,我们可以关闭这个开关
lintOptions {
abortOnError false
//即使报错也不会停止打包
checkReleaseBuilds false
//打包release版本的时候进行检测
}
compileSdkVersion 25 //指定项目的编译版本
buildToolsVersion "25.0.1"//指定项目构建工具的版本;其中包括了打包工具aapt、dx等等
defaultConfig {
applicationId "com.hhqy.learnndk2" //指定包名
minSdkVersion 14//指定最低的兼容的Android系统版本
targetSdkVersion 25//指定你的目标版本,表示你在该Android系统版本已经做过充分的测试
versionCode 1 //版本号
versionName "1.0" //版本名称
multiDexEnabled true
//当方法数超过65535(方法的索引使用的是一个short值,
//而short最大值是65535)的时候允许打包成多个dex文件,动态加载dex。这里面坑很深啊
}
buildTypes { //指定生成安装文件的配置,常有两个子包:release,debug,
//注:直接运行的都是debug安装文件
release { //用于指定生成正式版安装文件的配置
minifyEnabled false //指定是否对代码进行混淆,true表示混淆
//指定混淆时使用的规则文件,proguard-android.txt指所有项目通用的混淆则,
//proguard-rules.pro当前项目特有的混淆规则
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-
rules.pro'
}
}
}
dependencies { //指定当前项目的所有依赖关系:本地依赖、库依赖、远程依赖
compile fileTree(dir: 'libs', include: ['*.jar'])//本地依赖
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.1'//远程依赖,com.android.support是域名
//部分,appcompat-v7是组名称,25.0.1是版本号
compile project(':hello')//库依赖
testCompile 'junit:junit:4.12' //声明测试用列库
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7'
}
//声明是要使用谷歌服务框架
apply plugin: 'com.google.gms.google-services'
//使用maven仓库。android有两个标准的library文件服务器,一个jcenter一个maven。两者毫无关系。 //jcenter有的maven可能没有,反之亦然。
//如果要使用jcenter的话就把mavenCentral()替换成jcenter()
repositories {
mavenCentral()
}
(3)gradle的版本问题
想必大家在引入其他工程的时候都会遇到这样的问题,导入的工程无法编译成功,所有的Java文件的标志都是红色的j而不是蓝色的C。这就是gradle的版本信息和gradle插件版本信息不对应造成的。
a.gradle插件版本位置:
project对应的build.gradle文件中classpath的内容
b.gradle版本配置位置:
gradle/wrapper/gradle-wrapper.properties文件中
distributionUrl=http\://services.gradle.org/distributions/gradle-3.3-all.zip
c.版本对应关系如下:
Plugin version | Required Gradle version |
---|---|
1.0.0 - 1.1.3 | 2.2.1 - 2.3 |
1.2.0 - 1.3.1 | 2.2.1 - 2.9 |
1.5.0 | 2.2.1 - 2.13 |
2.0.0 - 2.1.2 | 2.10 - 2.13 |
2.1.3 - 2.2.3 | 2.14.1+ |
2.3.0+ | 3.3+ |
3.0.0+ | 4.1+ |
3.1.0+ | 4.4+ |
3.2.0 - 3.2.1 | 4.6+ |
3.3.0 | 4.10.1+ |
官网链接:https://developer.android.google.cn/studio/releases/gradle-plugin#updating-plugin
参考链接:https://www.jianshu.com/p/c9ec9e2a506e