从编程的角度理解gradle脚本??Android Studio脚本构建和编程

本篇文章由嵌入式企鹅圈原创团队、魅族资深工程师degao撰写!

随着Android 开发环境从Eclipse转向Android Studio,我们每个人都开始或多或少要接触gradle脚本,大多数人将gradle看做构建工具,出现问题不知如何着手分析,只能寄希望百度能找到解决方案,其实大可不必。

如果我们把gradle看做编程框架,并理清gradle脚本与gradle对象的关系,通过查阅文档,不但能清晰理解gradle脚本,而且出现问题再也不用百度,通过查阅文档就能轻松解决问题。

本文就通过一个最普通的gradle工程,告诉大家如何通过查阅api文档来看懂Android里面的gradle 脚本。

一、gradle介绍

gradle基于的语言是groovy,而groovy语言是基于java语言的一个扩展,它完全兼容java语言的类库,所以在gralde脚本中你完全可以使用你熟悉的java语言来编程。在本文最后我们会给出一个直接在gradle脚本中使用java编程的例子。

由于本文仅仅是让大家能看懂脚本,而不是自己去编写,所以groovy和gradle的细节不是本文的重点,有需要的同学自行百度。这里要提的一点是groovy语言的函数调用是虽然和java类似,但是它是可以省略括号的,特别是当它的最后一个参数是闭包的时候。

println(“aaa” )//这个是可以的,

println“aaa” //这个也没有问题。

是不是发现了一个秘密:我们在gradle脚本里全是各种函数调用!!

Gradle api文档路径:https://docs.gradle.org/current/dsl/

由于我们也用到了Android 插件,所以我们也需要插件的文档,这个文档比较特殊,它是一个git工程,在线浏览老是显示html的源码而非页面,所以我建议大家将它clone回本地,然后用浏览器打开,工程地址:https://github.com/google/android-gradle-dsl.git

二、gradle脚本和gradle 类对应关系

稍稍浏览下gradle的文档,我们会发现工程里面的gradle脚本,其实和gradle的对象是对应的:

1.Gradle:全局对象,一次gradle构建对应一个Gradle对象;

2.Project:每个工程都是一个Project对象,它对应一个build.gradle文件;

3.Settings:对应一个Setting.gradle文件;

4.Task:代表要执行的工作,一个Project会有一个或多个Task用于完成构建的工作,Project会通过合理设置Task之间的依赖来组织构建流程,完成最终的构建任务。

三、脚本执行流程与对象生成

1.每次调用gradle 执行时,会先生成一个Gradle对象,里面保存一些全局的信息;

2.然后会解析setting.gradle,生成Settings对象,一般在setting.gradle中主要是调用include方法,导入工程下的各个子模块;

3.接下来会执行导入的各个子工程的build.gradle,生成并配置Project对象;

一般在build.gradle中,会调用Project的apply方法,引入插件,在插件中完成定义各种属性以及创建所需的Task。

四、实例解析

我们以一个Android studio 默认app样例工程结构为例,工程包含的gradle脚本目录结构:

1. setting.gradle

setting.gradle只有一行语句:

include ‘:app‘

这里的include其实是Setting的一个函数,‘:app‘ 是函数调用的参数。

那我们在setting.gradle里面还能写什么呢?因为setting.gradle对应的是gradle中的Settings对象,那查下Settings的文档(https://docs.gradle.org/current/dsl/org.gradle.api.initialization.Settings.html),看下它都有哪些方法,哪些属性,就知道在setting.gradle能写什么了:

比如:

include ‘:Common‘

project(‘:Common‘).projectDir = new File(settingsDir,‘../../SDK/Common/‘)//include 调用后,生成了一个名为:CommonProject对象,project(‘:Common‘)取出这个对象,设置ProjectprojectDir属性。

那projectDir哪里来的?请看Project类的文档。

2. build.gradle

接下来我们来看build.gradle,build.gradle对应一个Project对象,而Project本身是一个Build script:

而BuildScript可以包含哪些东西呢?

是不是看到了很多老朋友?buildscript , dependencies 。。

看了这里我们应该就能明白在build.gradle里面可以写哪些东西了。

这里要说明的一个重要的点是buildscript,任何一个build.gradle执行的时候,会优先处理buildscript,它是来给脚本建立运行环境的,什么是运行环境?

一般而言就是下载所需要的插件,举个例子,android工程都需要android插件,它们都是通过下面的方式引入的:

buildscript {

repositories {//告诉如果本地没有缓存,去哪个远程仓库下载插件

mavenCentral()

}

dependencies {

//这就是我们在applyplugin:com.android.application时的插件jar

classpath ‘com.android.tools.build:gradle:1.3.0‘

// NOTE: Do not place your application dependencies here; theybelong

//in the individual module build.gradle files

}

}

repositories {//告诉如果本地没有缓存,去哪个远程仓库下载编译时依赖的库

mavenCentral()

}

上面的repositories, dependencies都是函数调用哦~~

看到上面的两个一模一样的repositories 了吗?他们的作用是不一样的,在buildscript里面的那个是插件初始化环境用的,用于设定插件的下载仓库,而外面的这个是设定工程依赖的一些远程library的下载仓库的。

在build.gradle中引入插件,是我们常见的动作:

apply plugin: ‘com.android.application‘

查阅Project的文档(https://docs.gradle.org/current/dsl/org.gradle.api.Project.html).apply是Project的一个方法,

3. android相关部分

查阅android插件的文档:(file:///home/test/android-gradle-dsl/1.5/index.html)

上面就是我们在android{}里面能写的所有block的信息,然后在每个block里面能写什么继续点击进去察看有哪些属性和方法就可以了,

比如signingConfigs:

signingConfigs{

release {

storeFile file(‘../sign/release.jks‘)

storePassword "[email protected]!d"

keyAlias "small"

keyPassword"[email protected]!d"

}

}

本文至此可以告一段落,相信大家结合文档应该能弄明白gradle脚本里面的每个代码块的意义了。

五、Android工程间的父子关系

需要补充的是:上面例子工程的结构中,工程之间是存在父子关系的,比如RxJava-Android-Samples/build.gradle对应的Project是RxJava-Android-Samples/app/build.gradle对应的Project的父亲,而在父Project中做的操作是会被子Project继承的,比如如果在 父Project引入过了android 插件,则在子Project中可直接引用,不需要重写一个buildscript块。

1.   RxJava-Android-Samples/build.gradle

buildscript {

repositories {

mavenCentral()

}

dependencies {

classpath ‘com.android.tools.build:gradle:1.3.0‘

// NOTE: Do not place your application dependencies here; theybelong

//in the individual module build.gradle files

}

}

allprojects {

repositories {

mavenCentral()

}

}

2.   RxJava-Android-Samples/app/build.gradle

//直接引用android插件,没有buildscript准备插件;

apply plugin:‘com.android.application‘

dependencies {

compile ‘com.android.support:support-v13:23.0.1‘

compile ‘io.reactivex:rxandroid:1.0.1‘

// BecauseRxAndroid releases are few and far between, it is recommended you also

// explicitly depend on RxJava‘slatest version for bug fixes and new features.

compile ‘io.reactivex:rxjava:1.0.14‘

compile ‘io.reactivex:rxjava-math:1.0.0‘

compile ‘com.jakewharton.rxbinding:rxbinding:0.2.0‘

compile ‘com.jakewharton:butterknife:5.1.1‘

compile ‘com.jakewharton.timber:timber:2.4.2‘

compile ‘com.squareup.retrofit:retrofit:1.6.1‘

compile ‘com.squareup.okhttp:okhttp:2.0.0‘

compile ‘com.squareup.okhttp:okhttp-urlconnection:2.0.0‘

compile ‘com.alibaba:fastjson:1.2.4‘

debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.3‘

releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.3‘

}

android {

compileSdkVersion 23

buildToolsVersion ‘23.0.1‘

defaultConfig {

applicationId "com.morihacky.android.rxjava"

minSdkVersion14

targetSdkVersion22

versionCode1

versionName"1.0"

}

buildTypes {

release {

minifyEnabled true

proguardFilesgetDefaultProguardFile(‘proguard-android.txt‘),‘proguard-rules.pro‘

}

}

}

六、在gradle中使用java语言编程的例子

直接上代码,想学习的就劳心理解啦,编辑器对代码不太友好啊。

1. build.gradle

buildscript {

repositories{

maven {

url ‘http://artifactory.rnd.meizu.com/artifactory/all‘

}

}

dependencies {

classpath ‘org.aspectj:aspectjtools:1.8.6‘

}

}

importorg.aspectj.bridge.IMessage

import org.aspectj.bridge.MessageHandler

importorg.aspectj.tools.ajc.Main

dependencies{

compile‘org.aspectj:aspectjrt:1.8.6‘

}

android.applicationVariants.all{ variant ->

JavaCompile javaCompile = variant.javaCompile

//println javaCompile.properties

javaCompile.doLast {

String[] args = [

"-showWeaveInfo",

"-1.5",

"-inpath", javaCompile.destinationDir.toString(),

"-aspectpath",javaCompile.classpath.asPath,

"-d", javaCompile.destinationDir.toString(),

"-classpath",javaCompile.classpath.asPath,

"-bootclasspath",android.bootClasspath.join(File.pathSeparator)

]

MessageHandler handler = newMessageHandler(true);

new Main().run(args, handler)

def log = project.logger

for (IMessage message : handler.getMessages(null,true)) {

switch (message.getKind()) {

case IMessage.ABORT:

case IMessage.ERROR:

case IMessage.FAIL:

log.error message.message,message.thrown

break;

case IMessage.WARNING:

case IMessage.INFO:

log.info message.message,message.thrown

break;

case IMessage.DEBUG:

log.debug message.message,message.thrown

break;

}

}

println "aspect args : " +args.toString()

}

}

2. groovy

下面这段代码展示了groovy中变量定义,函数定义,List,Map,Range,闭包。

1)变量定义

defvariable1 = 1   //可以不使用分号结尾

2)函数定义;

StringtestFunction(arg1,arg2){//无需指定参数类型

...

}

3)List变量由[]定义,比如

defaList = [5,‘string‘,true] //List由[]定义,其元素可以是任何对象

4)List存取

aList[100]= 100 //设置第101个元素的值为10

assertaList[100] == 100

5)Map变量由[:]定义,比如

defaMap = [‘key1‘:‘value1‘,‘key2‘:true]

Map由[:]定义,注意其中的冒号。冒号左边是key,右边是Value。key必须是字符串,value可以是任何对象。另外,key可以用‘‘或""包起来,也可以不用引号包起来。比如:

defaNewMap = [key1:"value",key2:true]//其中的key1和key2默认被处理成字符串"key1"和"key2"

不过Key要是不使用引号包起来的话,也会带来一定混淆,比如

defkey1="wowo"

defaConfusedMap=[key1:"who am i?"]

//aConfuseMap中的key1到底是"key1"还是变量key1的值“wowo”?显然,答案是字符串"key1"。如果要是"wowo"的话,则aConfusedMap的定义必须设置成:

defaConfusedMap=[(key1):"who am i?"]

6)Range类,Range类型的变量 由begin值+两个点+end值表示

def aRange =1..5

//如果不想包含最后一个元素,则

defaRangeWithoutEnd = 1..<5

//包含1,2,3,4这4个元素

7)闭包

defxxx = {paramters -> code}  //或者

defxxx = {无参数,纯code}

比如:

defgreeting = { "Hello, $it!" }

assertgreeting(‘Patrick‘) == ‘Hello, Patrick!‘

当函数的最后一个参数是闭包的话,可以省略圆括号;

public static<T> List<T>each(List<T> self, Closure closure)

上面这个函数表示针对List的每一个元素都会调用closure做一些处理。这里的closure,就有点回调函数的感觉。但是,在使用这个each函数的时候,我们传递一个怎样的Closure进去呢?比如:

def iamList =[1,2,3,4,5]  //定义一个List

iamList.each{//调用它的each,这段代码的格式看不懂了吧?each是个函数,圆括号去哪了?

println it

}

上面代码有以下知识点:

each函数调用的圆括号不见了!原来,Groovy中,当函数的最后一个参数是闭包的话,可以省略圆括号。比如

deftestClosure(int a1,String b1, Closure closure){

//dosomething

closure() //调用闭包

}

那么调用的时候,就可以免括号!

testClosure4, "test", {

println"i am in closure"

}

开始你的Gradle构建和编程之旅吧~~

更多的嵌入式linux和android、物联网、汽车自动驾驶等领域原创技术分享请关注微信公众号:

时间: 2024-07-30 09:58:58

从编程的角度理解gradle脚本??Android Studio脚本构建和编程的相关文章

解决使用gradle或者Android Studio会遇到一些网络障碍

使用gradle 或者 Android Studio会遇到一些网络障碍.这些障碍,使用红杏为开发者开放的免费的公益代理可以解决. 红杏的公益代理,专门为开发人员开放,免费使用 参考网址: 1. http://www.liaohuqiu.net/cn/posts/about-red-apricot-and-compiling-fresco/ 2.http://blog.honx.in/dev-only/

Android studio 下的aidl编程实现Android的夸进程间通信

前言 Android中夸进程间通信方式有很多种方式,比如:aidl,Messenger,文件共享,广播(BroadCast),ContentProvider,Socket(网络通信).每种方式都有自己的使用场景和优缺点,接下来几篇博客我们一一学习他们是怎么使用的.这篇博客主要是介绍Android studio下实现aidl编程. AIDL的使用步骤 aidl远程调用传递的参数和返回值支持Java的基本类型(int long booen char byte等)和String,List,Map等.当

Android Studio下构建Maven私服

Android Studio下构建Maven私服 对Maven的理解 Maven仓库的分类 本地Maven仓库和远程Maven仓库(中央仓库,第三方仓库,私服) jcenter和MavenCenter 略 搭建Maven私服 一.下载并安装Maven环境 需要注意的是:后面需要修改Settings setting文件3.0之前在C:\Users\xxx.m2下,其实AndroidStudio通过JCenter下载的jar即放在这个文件夹下.3.0之后在Maven目录的conf下 二.下载并安装N

理解与配置android studio中的gradle

使用gradle构建android应用时,你总是需要这样一个文件:build.gradle.你应该已经看过这个文件了,如果没有看过的话,你现在就可以看一下,它没有多少内容.它的简洁性得益于它提供了很多对设置和属性的默认值.gradle是基于groovy语言的,但就使用它构建普通的工程的话,是可以不去学groovy的,如果想深入的做一下自定义的构建插件,可以考虑学一下groovy,因为它是基于java的,所以你有java基础的话,学习不会很难. 这篇博客旨让任何一个人能看懂android stud

Android Studio的构建系统:Gradle

原文作者:youxiachai <用Gradle 构建你的android程序> 前言 android gradle 的插件终于把混淆代码的task集成进去了,加上最近,android studio 用的是gradle 来构建项目, 下定决心把android gralde 构建项目的用户指南全部看完, 让不会用gradle 的人也用gradle构建android项目,让打包(注意,打包和构建是两码事)多版本android不再痛苦.最后,题外话:珍惜生命,远离ant.... Gradle buil

Android 使用Gradle加Android Studio 多渠道打包

转载请注明出处: http://blog.csdn.net/jjwwmlp456/article/details/45057067  ----------------- 匆忙拥挤repeat Gradle,这个东西好复杂,不过在Android中,我们知道它大概怎么用,它的依据何来,就够了. Gradle的DSL,领域特定语言(domain-specific languages,简称DSL),地址:http://gradle.org/docs/2.3/dsl/ Gradle的用户指南,地址:htt

gradle/gradle plugin/Android studio关系

gradle - 构建工具,存储于Users/stono/.gradle/wrapper/dists Adroid Studio- IDE Gradle plugin - 在AS中使用Gradle的插件:貌似存储于:/Applications/Android Studio 3.0 Preview.app/Contents/gradle/m2repository/com/android/tools/build/gradle 三者之间有版本兼容问题: Gradle与Gradle plugin版本关系

jenkins+svn+android studio自动化构建(持续集成)

先到Jenkins官网的Meet Jekins中看一下Installation部分,原文如下 You have several options for downloading and installing Jenkins: *Use one of the platform-specific package/installer links on the Jenkins site to install Jenkins on your system. *You can download jenkins

Android Studio项目构建常见问题解决

1. 创建或导入项目后编译时一直在等待 问题: 原因:AS连网去下载gradle了,但是网络不好或不通 解决:禁用网络,AS就会立即自动终止下载进入到主界面了.此时再去指定离线的gradle版本进行编译: 2. Unknow host ‘services.gradle.org’ 问题: 原因:当你导入第三方项目时,别人项目使用的gradle的版本与你的不一样,这时as就会连网去下载gradle版本,但是找不到services.gradle.org服务器. 解决:不一定要去下载不同的gradle版