Gradle总结《二》---Gradle与Maven

Gradle

安装

准备阶段

Gradle 需要运行在一个 Java 环境里,因此安装Gradle前需要先安装JDK

安装一个 Java JDK 或者 JRE. 而且 Java 版本必须至少是 6 以上. Gradle 自带 Groovy 库,
所以没必要安装 Groovy. 任何已经安装的 Groovy 会被 Gradle 忽略.

下载

  1. 下载: 你可以从 Gradle网站 下载任意一个已经发布的版本
  2. 解压后大致可以看到以下内容:
    Gradle总结《二》---Gradle与Maven_第1张图片
    • Gradle 的二进制文件.
    • 用户指南 (HTML 和 PDF).
    • DSL参考指南.
    • API文档 (Javadoc和 Groovydoc).
    • 扩展的例子,包括用户指南中引用的实例,以及一些更复杂的实例来帮助用户构建自己的build.
    • 二进制源码.此代码仅供参考.

设置环境变量

  1. 添加一个 GRADLE_HOME 环境变量来指明 Gradle 的安装路径
  2. 添加 GRADLE_HOME/bin 到您的 PATH 环境变量中. 通常, 这样已经足够运行Gradle了.

扩充教程

Max OX: 假设您下载好的 Gradle 文件在 /Users/UFreedom/gradle 目录
1. vim ~/.bash_profile

2.添加下面内容: export GRADLE_HOME = /Users/UFreedom/gradle export export PATH= PATH: GRADLE_HOME/bin

3.source ~/.brash_profile 实际配置中,您需要将上面的目录换成您的 Gradle 文件在系统中的目录.

运行并测试您的安装

我们可以通过在控制台输入 gradle 命令来运行Gradle. 通过 gradle -v 命令来检测Gradle是否已经正确安装. 如果正确安装,会输出Gradle版本信息以及本地的配置环境 ( groovy 和 JVM 版本等). 显示的版本信息应该与您所下载的 gradle 版本信息相匹配. 如:

Gradle总结《二》---Gradle与Maven_第2张图片

Gradle Wrapper

为什么需要Gradle Wrapper

  1. 有些软件(应用)需要设备上先安装Gradle才能正常使用(如Android Studio,下文简称AS),因此为了避免这种情况,Gradle提供了一个Wrapper,使得Gradle可以像是被集成在AS中一样(只要安装AS即可)。
  2. 另外还考虑到一种情况:我们不能确保设备上已有的Gradle版本适用于我们需要使用的软件。有可能Gradle的版本过老而导致和下载的软件版本不兼容。

因此Gradle Wrapper即可认为是对Gradle进行封装,简单的理解(Gradle Wrapper = Gradle + 相关的集成、运行脚本文件)。

使用Wrapper

Gradle Wrapper的使用与Gradle略微不同,他的指令为:

  • ./gradlew (on Unix-like platforms such as Linux and Mac OS X)
  • gradlew (on Windows using the gradlew.bat batch file)

这里需要说明的是,Gradle Wrapper初始状态是不包含Gradle文件,而是以配置的方式让你可以方便的进行操作。如配置Gradle的下载路径:

distributionUrl = https\://services.gradle.org/distributions/gradle-3.1-all.zip

当第一次执行gradlew命令是,会检查本地是否存在对应的Gradle版本,如果不存在则会先下载对应版本。这个在“Gradle在Android中的应用”中的Gradle版本升级中提到过。

Gradle能做什么(命令行)

Gradle的安装我们在前面的章节提到过了,用gradle -v确认安装成功就可以继续接下来的工作了。

先看看Gradle自带哪些功能

使用gradle tasks可以看到,Gradle自带的(目前可用的)Task基本都是一些类似帮助使用的。
Gradle总结《二》---Gradle与Maven_第3张图片

Gradle初始化

新建一个Hello Gradle目录(D:\Hello Gradle),然后cmd窗口进入到改目录,先执行gradle init命令,可以看到自动生成Gradle相关的文件即目录,如下:
(.gradle = gradle脚本缓存文件 )

Gradle总结《二》---Gradle与Maven_第4张图片

help

我们可以通过gradle -h命令来查看,在执行task命令时还可以做哪些特定的操作

Gradle总结《二》---Gradle与Maven_第5张图片

任务(Task)的定义及使用

我们在HelloGradle\build.gradle中添加一下内容:

task compile << {
    println 'compiling source'
}

task compileTest(dependsOn: compile) << {
    println 'compiling unit tests'
}

task test1(dependsOn: [compile, compileTest]) << {
    println 'running unit tests'
}

task dist(dependsOn: [compile, test1]) << {
    println 'building the distribution'
}

这里有个重要的概念,就是这个dependsOn,如我们执行compileTest时,会先执行依赖的compile这个Task。这个在任务的定义及使用过程中非常常见且重要。
现在我们看一下执行gradle dist这个任务的结果:
Gradle总结《二》---Gradle与Maven_第6张图片

由于每个任务仅会被调用一次,所以调用gradle test test与调用gradle test效果是相同的.

help中的指令在运行Task时的应用

格式: gradle [option…] [task…]

  • -x, –exclude-task
    你可以用命令行选项-x来排除某些任务,如gradle dist -x test1,去除test1
  • -t, –continuous
    默认情况下, 只要有任务调用失败, Gradle就会中断执行. 这可能会使调用过程更快, 但那些后面隐藏的错误就没有办法发现了. 所以你可以使用 –continue 选项在一次调用中尽可能多的发现所有问题.
    采用 –continue 选项, Gralde 会调用每一个任务以及它们依赖的任务. 而不是一旦出现错误就会中断执行.所有错误信息都会在最后被列出来.
  • -b, –build-file
    调用 gradle 命令时, 默认情况下总是会构建当前目录下的文件, 可以使用 -b 参数选择其他目录的构建文件(并且当你使用此参数时 settings.gradle 将不会生效)
  • -p, –project-dir
    参数用以指定脚本目录即可.
  • -d, –deubg
    打印执行过程中log信息
  • -q, –quiet
    只打印错误(error)信息
  • –profile
    参数可以收集一些构建期间的信息(如构建时间)并保存到 build/reports/profile 目录下. 并且会以构建时间命名这些文件.

    最后,说一个比较重要的点,Gradle执行任务时,可以简化任务名,比如我们的dist任务(Task),就可以使用 gradle di,或者驼峰式的,如执行compileTask:gradle cT

Gui

黑窗口(cmd)在交互体验上难免欠缺,所以Gradle也是提供了图形化界面,用gradle -gui启动

Task tree

如果我们从自己的Gradle项目目录中启动这个图形界面,我们应该会看到任务树。可以看到我们之前定义的4个任务:
Gradle总结《二》---Gradle与Maven_第7张图片

Favorites

就是一个命令的收藏夹。

Command Line

将命令填入到gradle输入框. 就可以直接执行单个的Gradle命令.

Setup

设置界面

  • 列表内容“Current Directory”
    图形界面会默认设置您的Gradle项目的根目录(build.gradle 文件所在的目录)为当前目录.
  • “Stack Trace Output“
    这个选项可以指定当错误发生时,有多少信息可以写入到轨迹栈中,注意:在您设定轨迹栈级别后,如果”Command Line”(命令行)选项卡中,或者在”Favorites”(收藏夹)选项卡中的命令发生错误,这个设置就不会起作用了.
  • ”Only Show Output When Errors Occur”
    设定当编译出问题时输出窗口才显示相关信息.
  • “Use Custom Gradle Executor”
    高级功能,您可以指定一个路径启动Gradle命令代替默认的设置,例如您的项目需要在别的批处理文件或者shell脚本进行额外的配置(例如指定一个初始化脚本),这种情况您就可以使用它.
    Gradle总结《二》---Gradle与Maven_第8张图片

创建一个Java项目

该章节,准备用 Gradle 来构建运行 hello world 程序,体会一下不用任何 IDE ,只用 Gradle (构建工具)是咋回事,然后我们再继续核心概念的介绍。 为了方便起见,我们选择JAVA项目而不是Android项目。

创建一个新项目

由上个章节可以看出,Gradle init的目录结构还不是我们想要的Java的结构,其实也比较好理解,我们知道Gradle是独立存在的,所以要创建Java项目,我们必须借用Java Plugin(关于插件的内容后面将会介绍)。
清空目录下的内容(或新建一个空目录),然后使用命令gradle init –type java-library,这里我们指定了类型为Java,因此初始化完我们可以看到目录结构的变化:
Gradle总结《二》---Gradle与Maven_第9张图片

我们可以看到多了一个src目录,以及build.gradle文件的变化(之前的文件是个空内容):

// Apply the java plugin to add support for Java
apply plugin: 'java'

// In this section you declare where to find the dependencies of your project
repositories {
    // Use 'jcenter' for resolving your dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
}

// In this section you declare the dependencies for your production and test code
dependencies {
    // The production code uses the SLF4J logging API at compile time
    compile 'org.slf4j:slf4j-api:1.7.21'

    // Declare the dependency for your favourite test framework you want to use in your tests.
    // TestNG is also supported by the Gradle Test task. Just change the
    // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
    // 'test.useTestNG()' to your build script.
    testCompile 'junit:junit:4.12'
}

编辑java文件,并编译

我们可以看到在src/main/java下已经自动生成一个Library.java的文件,暂时不管这个。新建一个Main.java,并让他打印一句“Hello World”,保存后运行gradle build进行编译(构建):

//Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

Gradle总结《二》---Gradle与Maven_第10张图片

可以看到多了一个build目录,该目录下存放的即为gradle构建完产生的Main.class文件、HelloGradle.jar以及一些report文件等。

运行项目

为了可以正常运行项目,需要在build.gradle里面添加插件application ,并且制定入口(mainClassName),然后执行gradle run即可,结果见下图:
Gradle总结《二》---Gradle与Maven_第11张图片

小结

以上步骤,我们完全依靠Gradle(及相关插件)便完成了项目创建、编译、运行的过程。可以看到:
1. Gradle插件非常重要,正如我们之前提到的Gradle的设计理念“Gradle只负责一些最基础的任务,而特性化的功能都交于插件来封装与实现。”
2. 这个过程Gradle做的工作大概有:利用JDK将.java编译(javac)成.class,最终根据指定的入口运行(java).class文件。
3. 当然Gradle还有很多重要的功能,其中非常重要的依赖管理,将在后面进行介绍。

配置

我们可以同过添加gradle.properties文件来给Gradle添加一些附加配置。gradle.properties可以在项目目录下(针对当前项目),或者 gradle user home((window)/Users/”your pc_name”/.gradle)目录下。我们在说到统一依赖管理的时候有提到这个文件,可以利用他进行一些全局性的属性配置。先看几个Gradle自带的属性:

  • Gradle Daemon
    我们可以通过使用Dradle Daemon[‘diːmən]来减少Gradle的启动时间,他是一个后台常驻进程(3个小时不被调用会自动结束),会在你下一次执行builds之前的空闲时间中做一些预处理工作,如缓存项目结构、文件等信息。 Gradel Daemon将在Gradle3.0+的版本中默认开启,也可以在项目的gradle.properties中添加:
    org.gradle.daemon = true

  • Parallel Project Execution
    当你项目中有多个子module时,这个配置显得尤为重要,同样可以在项目的gradle.properties中添加:
    org.gradle.parallel = true

  • Configure projects on demand
    按需配置(Configuration ondemand)只对任务相关的项目进行配置,这在大型多项目编译过程中非常有用,能够大幅度的减少不必要的配置时间。

附:提高构建速度的配置

# The Gradle daemon aims to improve the startup and execution time of Gradle.
# When set to true the Gradle daemon is to run the build.
#我们可以通过使用Dradle Daemon来减少Gradle的启动时间,他是一个后台常驻进程,会在你下一次执行builds之前的空闲时间中做一些预处理工作,
#如缓存项目结构、文件等信息。Gradel Daemon将在Gradle3.0+的版本中默认开启
org.gradle.daemon=true

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
#http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
#(并行模式)当你项目中有多个子module时,这个配置显得尤为重要
org.gradle.parallel=true

# Enables new incubating mode that makes Gradle selective when configuring projects.
# Only relevant projects are configured which results in faster builds for large multi-projects.
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:configuration_on_demand
# 按需配置(Configuration ondemand)只对任务相关的项目进行配置,这在大型多项目编译过程中非常有用,能够大幅度的减少不必要的配置时间。
org.gradle.configureondemand=true

另外,还有比较常见的用法,即利用该文件来配置网络代理,如:

systemProp.http.proxyHost=www.somehost.org
systemProp.http.proxyPort=8080
systemProp.http.proxyUser=userid
systemProp.http.proxyPassword=password
systemProp.http.nonProxyHosts=*.nonproxyrepos.com|localhost

Maven

前言

我们知道Gradle是在Ant与Maven的基础上优化而来的,而Maven在Ant的基础上进行改进的。对于Ant,他主要是处理打包构建的流程,其用Task进行工作的设计被Gradle继承与完善,但是他不支持依赖管理这一功能,这也是使用Eclipse(采用Ant)时,需要使用第三方包总是需要我们自己手动添加jar包。当然,这章我们主要讲Maven,因为他更接近Gradle,并且我们在上传jar或aar包(至Maven仓库)时,需要采用Maven插件,这就要求我们需要去了解相关的知识。

核心概念

POM (Project Object Model)

一个项目所有的配置都放置在 POM 文件中:定义项目的类型、名字,管理依赖关系,定制插件的行为等等(我们可以理解为,POM文件对于Maven就相当于.build文件对于Gradle中。Pom中的配置语言是xml,build中的是Groovy)。一下看一个简单示例:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0modelVersion> 

     <groupId>com.mycompany.helloworldgroupId> 
     <artifactId>helloworldartifactId> 
     <version>1.0-SNAPSHOTversion> 
     <packaging>jarpackaging> 

     <name>helloworldname> 
     <url>http://maven.apache.orgurl> 

     <properties> 
       <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> 
     properties> 

     <dependencies>
       <dependency> 
         <groupId>junitgroupId> 
         <artifactId>junitartifactId> 
         <version>4.12version> 
         <scope>testscope> 
       dependency> 
     dependencies> 
    project>    

Maven的习惯是通过 groupID(一般是组织的域名倒写,遵循Java package的命名习惯)+ artifactId(库本身的名称) + version(版本)来定义坐标, packaging用来表示包的类型,如jar或aar等。有了 maven 坐标,我们就可以用它来指定我们的项目所依赖的其他项目,插件,或者父项目。一般 maven 坐标写成如下的格式:

groupId:artifactId:packaging:version

像我们的例子就会写成:

com.mycompany.helloworld: helloworld: jar: 1.0-SNAPSHOT

Maven 依赖管理

前面我们说过,maven 坐标能够确定一个项目。换句话说,我们可以用它来解决依赖关系。在 POM 中,依赖关系是在 dependencies 部分中定义的。在上面的 POM 例子中,我们用 dependencies 定义了对于 junit 的依赖:

<dependencies> 
  <dependency> 
    <groupId>junitgroupId> 
    <artifactId>junitartifactId> 
    <version>4.12version> 
    <scope>testscope> 
  dependency> 
dependencies> 

这个例子很简单,但是实际开发中我们会有复杂得多的依赖关系,因为被依赖的 jar 文件会有自己的依赖关系。那么我们是不是需要把那些间接依赖的 jar 文件也都定义在POM中呢?答案是不需要,因为 maven 提供了传递依赖的特性。

所谓传递依赖是指 maven 会检查被依赖的 jar 文件,把它的依赖关系纳入最终解决的依赖关系链中。依赖关系会存在一份POM文件中,在添加(下载)jar包的时候同时会下载POM文件,这样 maven 就能检查 junit 的依赖关系,把它所需要的依赖也包括进来。

在 POM 的 dependencies 部分中,scope 决定了依赖关系的适用范围。我们的例子中 junit 的 scope 是 test,那么它只会在执行 compiler:testCompile and surefire:test 目标的时候才会被加到 classpath 中,在执行 compiler:compile 目标时是拿不到 junit 的。scope 的默认值是 compile,即任何时候都会被包含在 classpath 中,在打包的时候也会被包括进去。

Gradle和Maven在依赖管理上几乎差不多,核心的概念是一样的,只不过Gradle语法更精简,如上面的依赖等价于:testCompile ‘junit:junit:4.12’,并且多了一些更灵活的自定义配置。

maven_vs_gradle

Maven仓库

在Maven中,任何一个依赖、插件或者项目构建的输出,都可以称之为构件。Maven在某个统一的位置存储所有项目的共享的构件,这个统一的位置,我们就称之为仓库,简单说:仓库就是存放依赖和插件的地方。(Gradle沿用了Maven仓库的使用)
Maven仓库分为两类:本地仓库和远程仓库(在远程仓库中又分成了3种:中央仓库 、 私服 、 其它公共库)
- 本地仓库
本地仓库,顾名思义,就是Maven在本地存储构件的地方。maven的本地仓库,在安装maven后并不会创建,它是在第一次执行maven命令的时候才被创建。maven本地仓库的默认位置:无论是Windows还是Linux,在用户的目录下都有一个.m2/repository/的仓库目录,这就是Maven仓库的默认位置。

  • 远程仓库
    这个章节讲Maven仓库,主要是为了介绍Maven远程仓库。

    • 中央仓库
      说到远程仓库就先从最核心的中央仓库开始,中央仓库是默认的远程仓库,maven在安装的时候,自带的就是中央仓库的配置。中央仓库包含了绝大多数流行的开源Java(Android)构件,以及源码、作者信息、SCM、信息、许可证信息等。一般来说,简单的Java(Android)项目依赖的构件都可以在这里下载到。

      在Android Studio中默认采用的中央(Maven)仓库为jcenter,之前默认为mavenCentral(似乎这个名字更直观),简单理解jcenter在效能、使用、安全上都优于mavenCentral这个就行。

    • 私服
      私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构件的时候,它从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再为Maven的下载请求提供服务。我们还可以把一些无法从外部仓库下载到的构件上传到私服上。
      Maven私服的 个特性:

      1. 节省自己的外网带宽:减少重复请求造成的外网带宽消耗
      2. 加速Maven构件:如果项目配置了很多外部远程仓库的时候,构建速度就会大大降低
      3. 部署第三方构件:有些构件无法从外部仓库获得的时候,我们可以把这些构件部署到内部仓库(私服)中,供内部maven项目使用
      4. 提高稳定性,增强控制:Internet不稳定的时候,maven构建也会变的不稳定,一些私服软件还提供了其他的功能
      5. 降低中央仓库的负荷:maven中央仓库被请求的数量是巨大的,配置私服也可以大大降低中央仓库的压力

      当前主流的maven私服:

      • Apache的Archiva
      • JFrog的Artifactory
      • Sonatype的Nexus

上传构件至Maven仓库

以上讲完Maven的相关特性后,我们来看看其在Gradle的应用。如,上传构件至Artifactory仓库(对于Artifactory在服务器中配置相关我们这里就不介绍了):

添加相关插件

我们知道,在Gradle中,特性功能都是由插件来实现的,因此这个也必然需要我们添加相应的插件。

  • 在最上层的(project)build.gradle文件添加一个关于Artifactory Gradle 插件的依赖:
    buildscript {
        dependencies {
            classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.1.1"
        }
    }
  • 接下来,我们可以新建一个.build文件,并添加两个插件:一个准备Maven artifact maven-publish,另一个上传archives到artifactory com.jfrog.artifactory:
    apply plugin: 'com.jfrog.artifactory'
    apply plugin: 'maven-publish'

定义关键的参数

//服务端地址
def PUBLICAT_REPO_URL='your_url'
//仓库账号密码
def artifactory_username='username'
def artifactory_password='password'
//定位依赖
//Maven的习惯是通过 groupID(一般是组织的域名倒写,遵循Java package的命名习惯)+ artifactId(库本身的名称) + version(版本)来定义坐标
def ARTIFACT_ID = 'com-example-groupname'
def GROUP_ID = 'com.example.groupname'
def VERSION_NAME = '1.0.0'

配置需要上传的文件

现在我们需要利用maven-publish配置我们需要上传的内容

publishing {
    publications {
        //aar构件配置
        aar(MavenPublication) {
            groupId GROUP_ID
            version = VERSION_NAME
            artifactId ARTIFACT_ID

            // Tell maven to prepare the generated "* .aar" file for publishing
            // 指定我们需要上传的内容:outputs里的*-release.aar文件
            artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
         }

      //往pom文件中写入相关依赖(依赖传递)
       pom.withXml {
                def dependencies = asNode().appendNode('dependencies')
                configurations.getByName("_releaseCompile").getResolvedConfiguration().getFirstLevelModuleDependencies().each {
                    def dependency = dependencies.appendNode('dependency')
                    dependency.appendNode('groupId', it.moduleGroup)
                    dependency.appendNode('artifactId', it.moduleName)
                    dependency.appendNode('version', it.moduleVersion)
                }
            }
    }
}

指定发布的位置

我们需要利用com.jfrog.artifactory 插件来指定artifact发布到的库。

artifactory {
    //仓库地址
    contextUrl = PUBLICAT_REPO_URL
    publish {
        repository {
            //上传至指定的仓库(可以理解为指定目录)
            repoKey = 'libs-release-local'
            //仓库账号、密码
            username = artifactory_username
            password = artifactory_password
        }
        defaults {
            // Tell the Artifactory Plugin which artifacts should be published to Artifactory.
            publications('aar')
            publishArtifacts = true

            // Properties to be attached to the published artifacts.
            properties = ['qa.level': 'basic', 'dev.team': 'core']
            // Publish generated POM files to Artifactory (true by default)
            publishPom = true
        }
    }
}

执行

gradle generatePomFileForAarPublication artifactoryPublish -p *

你可能感兴趣的:(Gradle)