Gradle基础

最近需要做了一个功能,需要将Android工程中的一个lib库中所依赖的aar、jar等直接都打包,在最后的生成产物中-aar包含以上所有的依赖库;我们在开发Android过程中,也会遇到对编译过程进行干扰;当前Android工程的开发都是基于Gradle进行构建的,等等这些都要求对于Gradle我们需要进行一个比较全面的了解。

什么是Gradle

Gradle是一个开源的构建脚本工具,能够协助大家更好的提高开发效率;Gradle的构建脚本都是使用Groovy或者Kotlin或者Java编写的;Gradle提供了大量的API,我们可以根据这些API编写出自己的工具(Plugin-插件工具),利用自己编写的工具实现自己的需求,例如:复制文件、将特定文件目录的java源代码打包成jar包等。Gradle构建工具在最后还是启动了JVM,帮助自己干事情。

Gradle初体验

对于Gradle的安装可以参考官方文档,安装完成以后我们可以使用 gradle init(对于IDE创建工程,这个命令有IDE自己完成)命令初始化一个gradle构建的工程,查看当前的文件目录如下:

├── build.gradle
├── settings.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat

这个就是使用gradle构建一个工程必须的一些文件,这些文件的和我们创建的Android工程是不是有点类似呢。接下来对这些文件的用途做一个简单的介绍:
build.gradle:主要是为执行的一些task配置一些参数,或者在这里添加自己的参数等;对应与Android构建工程中,在该文件中配置了编译时使用的sdk版本、编译工具版本等参数;这里配置中最终要的一点就是需要使用哪些插件,使用了什么插件就是使用了哪些task;
setting.gradle:配置一下当前工程目录中,哪些子工程需要参与构建;
gralde:该目录中包含了gradle-wrapper.jar和gradle-wrapper.properties两个文件,其中jar包就是一个可执行的gradle,gradle-wrapper.properties主要是配置一些与这个可执行jar包相关的参数:

#Sun Mar 11 21:54:32 CST 2018
#分配的最基本的地址路径,主要是用于存储gradle.jar
distributionBase=GRADLE_USER_HOME 
#gradle.jar存储的相对路径,与前面的基本路径组合成了绝对路径
distributionPath=wrapper/dists    
#下载gradle.jar的zip类型文件存储的基本路径
zipStoreBase=GRADLE_USER_HOME     
#zip文件存储的相对路径,与前面的基本路径组合为绝对路径
zipStorePath=wrapper/dists        
#需要下载的对应版本gradl压缩包
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip  

gradlew与gradlew.bat:这两个文件都是可执行的脚本,功能都是相同的,只是对应不同系统下的执行脚本,分别对应Unix base和Window系统。执行该脚本的功能与直接在命令行执行gradle功能是相同的,那这个脚本存在的意义是什么呢,主要的意义在于可以执行特定版本的gradle,也就是上面gradle文件下的jar包,我们需要修改gradle-wrapper.properties下对应的属性,并重新执行gradlew脚本就会重新下载。

Gradle与插件

对于插件比较直观的体验就是安装了插件我可以使用特定的功能,例如在浏览器上安装了Octotree,我们在浏览Github上的开源工程的时候,可以在左侧直接查看工程目录。对于Gradle构建的工程,如果我们需要使用某些特定功能的构建工具,也是以插件的形式完成的。

插件的主要功能就是利用Gradle 定义的API实现自己的功能,前面已经说过Gradle开放了大量的API,这些API主要是定义了基本的一些功能:copy文件、文件打包为jar包等;对于Android开发来说比较常见的插件有下面两个:

//构建Android App的插件
apply plugin: 'com.android.application'
//构建Android Lib的插件
apply plugin: 'com.android.library'

其实上面的这些插件都是Android官方为广大开发者提供的,对于App构建的过程有了解过的人肯定比较清晰的知道,里面包括了R.java文件的生成、dex文件的生成、打包等;对于正常情况下如果不使用自动打包构建脚本,我们肯定需要使用Android提供的最原生的工具aapt、dx等按部就班的生成对应的文件和转换,最后打包压缩为APK文件。但是使用这些构建脚本可以大大提高我们的开发效率、发布效率、构建效率等。

自定义Gradle插件-自己动手

在构建自己的Gradle之前需要了解两个基本的API接口,方便更好的理解自己编写的Gradle插件。

基本知识点

Project

在前面初步体验Gradle的时候,简单的创建了一个Gradle构建工程,对于一个工程就对应与Gradle中的一个Project对象,Project对象里面定义了大量与该工程对应的变量、操作方法等。我们在使用 gradle 工具构建工程的时候会读取目录文件中的 build.gradle 文件,该文件配置了Project相关的属性;

Task

对于一个工程来说,当需要构建的时候肯定需要一步一步的完成某些步骤,最后产生自己需要的产物;对于Gradle构建来说,把这些一个一个的步骤对应了一个Task对象;还是以Android打包过程来进行分析,如果我们需要将当前的java原文件编译成class文件,这里就需要使用cmpileJava这个Task;对于Android打包的插件也就是定义了大量的Task,然后将这些Task添加到Project中,并定义好它们的顺序,在构建脚本启动的时候按照先前定义好的顺序,逐个执行这些Task,最终就会得到我们自己想要的产物—APK文件。

开始自定义

下面就开始来编写自己的插件,并执行运行该插件。首先需要创建一个Gradle构建工程,直接使用 gradle init 命令创建了我们在第一部分的工程目录:

├── build.gradle
├── settings.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat

然后使用如下命令创建目录:

mkdir -p buildSrc/src/main/java/com/github/songnick/example

然后创建文件:buildSrc/src/main/java/com/github/songnick/example/ExamplePlugin.java

package com.github.songnick.example;

import org.gradle.api.Plugin;
import org.gradle.api.Project;

public class ExamplePlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        project.getTasks().create("hello", HelloTask.class, (task) -> { 
            task.setMessage("Hello");
            task.setRecipient("World");                                
        });
    }
}

这里是实现了插件接口,并重写了apply方法,在该方法中使用project对象提供的接口定义了一个Task—HelloTask,这里的project对象就是上面的部分介绍到的,可以通过这个project对象获取工程构建的文件目录、依赖的库等信息。对于HelloTask类的具体定义如下:

buildSrc/src/main/java/com/github/songnick/example/HelloTask.java

package com.github.songnick.example;

import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.TaskAction;

public class HelloTask extends DefaultTask {
    private String message;
    private String recipient;

    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }

    public String getRecipient() { return recipient; }
    public void setRecipient(String recipient) { this.recipient = recipient; }

    //具体的任务执行注解
    @TaskAction
    void sayGreeting() {
        System.out.printf("%s, %s!\n", getMessage(), getRecipient()); 
    }
}

这里的@TaskAction注解表示最后调用这个任务的执行方法;
当我们创建和编写完成上面的文件以后,当前的文件目录结构就变为了:

├── build.gradle
├── buildSrc
│   └── src
│       └── main
│           └── java
│               └── com
│                   └── github
│                       └── songnick
│                           └── example
│                               ├── ExamplePlugin.java
│                               └── HelloTask.java
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

多出了buildSrc文件目录及里面的文件,这个时候直接执行 gradle命令或者./gradlew 这个时候就会编译buildSrc文件下的java文件,并生成了编译过后相关的产物,可以通过buildSrc/build/文件目录去查看对应的产物,其中包括class文件、jar包等。这里有可能比较疑惑,为什么执行这个命令会编译buildSrc文件下对应的文件,这个是gradle工具在执行构建的时候默认会把当前文件目录下的buildSrc文件作为自己的默认编译目录。现在我们编译完成了,怎么验证我们编写的插件是否能够正常使用呢,用编辑器打开当前目录中的build.gradle文件,并添加如下字段:

apply plugin: com.github.songnick.example.ExamplePlugin

然后执行 ./gradlew tasks 结果中会看到:

Other tasks-----------hello

这里就是我们通过自定义的插件添加的Task-名字叫hello;我们可以直接执行该task:./gradlew hello 查看结果。

上面是通过自己在命令行纯手工实现了一个自定义的插件以及Task,当然也可以通过其他IDE创建插件工程,并实现发布等,这些对应的教程也比较多,这里就不详细介绍。主要是希望通过上面简单的创建过程大家可以直接的感受一下自定义插件。

构建Gradle插件-编程语言

上面自定义插件的部分中,我们使用了Java语言编写了相关接口的实现、类的继承等;其实对于插件的编写Gradle构建工具还支持Groovy,对于语言来说我们不需要纠结太多,每个语言都有其特点;那么Gradle为啥要支持除了Java语言的Groovy语言呢,我个人的理解其实很简单,可以从Android工程使用Gradle构建看出,我们需要对工程做一些配置,这些配置都是放在 build.gradle 中,我们发现在配置这些参数的时候就是使用了Groovy语言的特性。对于Groovy语言是DSL(领域专用语言),这些语言的设计初衷是给非程序员使用,所以设计的时候就会更加的容易让人理解,使用起来更方便;对于Grooy语言的学习大家可以自行学习,这里就不过多的介绍了。

后记

简单的把Gradle的基础的基本概念和自己的理解阐述 了一下,更多的学习资料还是直接访问官网吧,对于插件的编写以及Groovy的学习可以直接学习Android构建插件的源码吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,380评论 25 707
  • 什么是 Gradle ? 所谓构建工具就是对你的项目进行编译、运行、签名、打包、依赖管理等一系列功能的合集,传统的...
    方子晗阅读 475评论 0 0
  • Gradle是基与Groovy的脚本配置的构筑工具,用与构筑Java及Android应用. Gradle Grad...
    花京院典明阅读 1,152评论 0 8
  • 突然又说到小时候, 想当年我是多爱说话, 想当年数学多简单, 想当年同学是多单纯, 想当年总喜欢表现, 想当年想哭...
    怎么都被用了呢阅读 211评论 2 5
  • 追求美是一种人的本能,虽然每个人心目中的美不尽相同,追求美的方式也千奇百怪。黑夜为灯提供了绽放异彩的土壤,...
    霸王东渡阅读 222评论 1 3