本文共 6546 字,大约阅读时间需要 21 分钟。
前言:
Gradle的使用方法已经被各个大神详细的讲解过了,最近我在项目中遇到了第三方jar冲突的解决方法,然后就终于详细的把Gradle的使用方法学习了一遍,感觉还是比较全面的,现在总结出来分享给大家。我在找资源的时候一般大家介绍的都比较零散,参考了一些文章我写一个全面的使用教程出来,希望初学者能够一次性的概览Gradle的所有方法。
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。
面向Java应用为主。当前其支持的语言限于Java、Groovy、Kotlin和Scala,计划未来将支持更多的语言。
好了这是百度给的答案,初学者有点晕米关系,我们一点点学习他如何用就可以了,使用过程中你会加深对他的理解。
Gradle 是 Android 现在主流的编译工具。他和 Android Studio 的关系非常紧密,对于一些简单的程序我们几乎不需要任何代码上的配置只使用 Android Studio 就可以完成编译和运行。但是对于一些比较复杂的,特别是多人团队合作的项目我们会需要一些个性化的配置来提高我们的开发效率。比如我们要自定义编译出的apk包的名字、对于一些特殊产品我们可能会要用同一个项目编译出免费版和付费版的apk。这些高级的功能都需要我们对配置代码进行自定义地修改。
在很多情况下我们都是使用的 Android Studio 来build、debug项目。Android Studio 能满足我们开发的大多数需求,但是某些情况下命令行能够让我们编译的效率更高,过程更明朗,一些高级的配置也需要熟悉命令行才能够使用,比如在服务器编译,某些项目初始化的时候如果直接交给Android Studio ,它会一直Loading,你都不知道它在干嘛,但是用命令行你就知道它卡在了哪个环节,你只需要修改某些代码,马上就能够编译过了。
we can do everything what we want.
在解析 Gradle 的编译过程之前我们需要理解在 Gradle 中非常重要的两个对象。Project和Task。
每个项目的编译至少有一个 Project,一个 build.gradle就代表一个project,每个project里面包含了多个task,task 里面又包含很多action,action是一个代码块,里面包含了需要被执行的代码。
在编译过程中, Gradle 会根据 build 相关文件,聚合所有的project和task,执行task 中的 action。因为 build.gradle文件中的task非常多,先执行哪个后执行那个需要一种逻辑来保证。这种逻辑就是依赖逻辑,几乎所有的Task 都需要依赖其他 task 来执行,没有被依赖的task 会首先被执行。所以到最后所有的 Task 会构成一个 有向无环图(DAG Directed Acyclic Graph)的数据结构。
编译过程分为三个阶段:
理解了Gradle是什么能做什么以后,我们来看下Android Studio(以下简称AS)中Gradle如何使用的。
MyApp
├── build.gradle ├── settings.gradle └── app ├── build.gradle ├── build ├── libs └── src └── main ├── java │ └── com.package.myapp └── res ├── drawable ├── layout └── etc.
上面是一个基本的AS工程的项目结构。
基于grade构建的项目通常至少有一个build.gradle,那么我们来看看project的build.gradle:buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.2.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' }}allprojects { repositories { jcenter() maven { url "https://jitpack.io" } }}task clean(type: Delete) { delete rootProject.buildDir}dependencies {}
这个就是实际构建开始的地方,在仓库地址中,我们使用了JCenter。这里我们要理解一个概念:仓库。本质上说,仓库是一种存放依赖的容器,每一个项目都具备一个或多个仓库。仓库实际上就是我们依赖的第三方开源库存放的地方。我们可以从这里下载我们所需的开发库。
grade只是一个构建工具,而新版本总是在更迭,所以使用Gradle Wrapper将会是一个好的选择去避免由于gradle版本更新导致的问题。Gradle Wrapper提供了一个windows的batch文件和其他系统的shell文件,当你使用这些脚本的时候,当前gradle版本将会被下载,并且会被自动用在项目的构建,所以每个开发者在构建自己app的时候只需要使用Wrapper。所以开发者不需要为你的电脑安装任何gradle版本,在mac上你只需要运行gradlew,而在windows上你只需要运行gradlew.bat。
你也可以利用命令行./gradlew -v来查看当前gradle版本。下列是wrapper的文件夹:
myapp/ ├── gradlew ├── gradlew.bat └── gradle/wrapper/ ├── gradle-wrapper.jar └── gradle-wrapper.properties
可以看到一个bat文件针对windows系统,一个shell脚本针对mac系统,一个jar文件,一个配置文件。配置文件包含以下信息:
#Sat May 30 17:41:49 CEST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/ gradle-2.4-all.zip
你可以改变该url来改变你的gradle版本。
Gradle 会根据build 文件的配置生成不同的task,我们可以直接单独执行每一个task。通过./gradlew tasks列出所有task。如果通过同时还想列出每个task 对应依赖的其他task,可以使用./gradlew tasks -all。
其实每当我们在Android Studio点击 build,rebuild,clean菜单的时候,执行的就是一些gradle task.
有四个基本的 task, Android 继承他们分别进行了自己的实现:
这些都是基本的命令,在实际项目中会根据不同的配置,会对这些task 设置不同的依赖。比如 默认的 assmeble 会依赖 assembleDebug 和assembleRelease,如果直接执行assmeble,最后会编译debug,和release 的所有版本出来。如果我们只需要编译debug 版本,我们可以运行assembleDebug。
除此之外还有一些常用的新增的其他命令,比如 install命令,会将编译后的apk 安装到连接的设备。
我们运行的许多命令除了会输出到命令行,还会在build文件夹下生产一份运行报告。比如check命令会生成lint-results.html.在build/outputs中。
使用你的命令行,导航到你的项目,然后输入:
$ gradlew tasks
这一命令将会列出所以可运行的tasks,你也可以添加–all参数,来查看所有的task。
当你在开发的时候,构建项目,你需要运行assemble task通过debug配置:
$ gradlew assembleDebug
该任务将会创建一个debug版本的app,同时Android插件会将其保存在MyApp/app/build/ outputs/apk目录下。
关于如何将eclipse项目导入Android studio本文不再介绍。
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') } }
在grade文件中配置,将会保存eclipse目录结构,当然,如果你有任何依赖的jar包,你需要告诉gradle它在哪儿,假设jar包会在一个叫做libs的文件夹内,那么你应该这么配置:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar'])}
该行意为:将libs文件夹中所有的jar文件视为依赖包。
我们前面看到的那些build.gradle 配置文件,和xml 等的配置文件不同,这些文件可以说就是可以执行的代码,只是他们的结构看起来通俗易懂,和配置文件没什么两样,这也是Google 之所以选择Groovy 的原因。除此之外,Groovy 是一门JVM 语言,也就是,Groovy 的代码最终也会被编译成JVM 字节码,交给虚拟机去执行,我们也可以直接反编译这些字节码文件。
我们这里简单地说一下 groovy 一些语法。
在groovy 中,没有固定的类型,变量可以通过def关键字引用,比如:
def name = 'Andy'
我们通过单引号引用一串字符串的时候这个字符串只是单纯的字符串,但是如果使用双引号引用,在字符串里面还支持插值操作,
def name = 'Andy'def greeting = "Hello, $name!"
类似 python 一样,通过def关键字定义一个方法。方法如果不指定返回值,默认返回最后一行代码的值。
def square(def num) { num * num}square 4
Groovy 也是通过class定义一个类:
class MyGroovyClass { String greeting String getGreeting() { return 'Hello!' }}
在 Groovy 中,定义一个列表是这样的:
List list = [1, 2, 3, 4, 5]
遍历一个列表是这样的:
list.each() { element -> println element}
定义一个 map 是这样的:
Map pizzaPrices = [margherita:10, pepperoni:12]
获取一个map 值是这样的:
pizzaPrices.get('pepperoni')pizzaPrices['pepperoni']pizzaPrices.pepperoni
在Groovy 中有一个闭包的概念。闭包可以理解为就是 Java 中的匿名内部类。闭包支持类似lamda形式的语法调用。如下:
def square = { num -> num * num}square 8
如果只有一个参数,我们甚至可以省略这个参数,默认使用it作为参数,最后代码是这样的:
Closure square = { it * it}square 16
理解闭包的语法后,我们会发现,其实在我们之前的配置文件里,android,dependencies这些后面紧跟的代码块,都是一个闭包而已。*
了解完 groovy 的基本语法后,我们来看看 gradle 里面的代码就好理解多了。
apply plugin: 'com.android.application'
这段代码其实就是调用了project对象的apply方法,传入了一个以plugin为key的map。完整写出来就是这样的:
project.apply([plugin: 'com.android.application'])
dependencies { compile 'com.android.support:multidex:1.0.0'}
实际调用的时候会传入一个DependencyHandler的闭包,代码如下:
参考文章: