Gradle&Maven-Gradle专题

Posted Android和Java技术驿站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gradle&Maven-Gradle专题相关的知识,希望对你有一定的参考价值。

Gradle专题

随着 GoogleEclipse的无情抛弃以及 Studio的不断壮大, android开发者逐渐拜倒在 Studio的石榴裙下。
而作为 Studio的默认编译方式, Gradle已逐渐普及。我最开始是被它的多渠道打包所吸引。

接下来我们就系统的学习一下 Gradle

简介

Gradle是以 Groovy语言为基础,面向 Java应用为主。基于 DSL(DomainSpecificLanguage)语法的自动化构建工具。

Gradle集合了 Ant的灵活性和强大功能,同时也集合了 Maven的依赖管理和约定,从而创造了一个更有效的构建方式。凭借 GroovyDSL和创新打包方式, Gradle提供了一个可声明的方式,并在合理默认值的基础上描述所有类型的构建。 Gradle目前已被选作许多开源项目的构建系统。

因为 Gradle是基于 DSL语法的,如果想看到 build.gradle文件中全部可以选项的配置,可以看这里DSL Reference

基本的项目设置

一个 Gradle项目通过一个在项目根目录中的 build.gradle文件来描述它的构建。

简单的 Build文件

最简单的 Android应用中的 build.gradle都会包含以下几个配置:
Project根目录的 build.gradle:

 
   
   
 
  1. buildscript {

  2.    repositories {

  3.        jcenter()

  4.    }

  5.    dependencies {

  6.        classpath 'com.android.tools.build:gradle:1.5.0'

  7.        // NOTE: Do not place your application dependencies here; they belong

  8.        // in the individual module build.gradle files

  9.    }

  10. }

Module中的 build.gradle:

 
   
   
 
  1. apply plugin: 'com.android.application'

  2. android {

  3.    compileSdkVersion 23

  4.    buildToolsVersion "23.0.3"

  5.    ...

  6. }

  • buildscript{...}配置了编译时的代码驱动. 这种情况下,它声明所使用的是 jCenter仓库。还有一个声明所依赖的在 Maven文件的路径。这里声明的包含了 Android插件所使用的1.5.0版本的 Gradle. 注意:这只会影响 build中运行的代码,不是项目中。项目中需要声明它自己所需要仓库和依赖关系。

  • apply plugin:com.android.application,声明使用 com.androdi.application插件。这是构建 Android应用所需要的插件。

  • android{...}配置了所有 Android构建时的参数。默认情况下,只有编译的目标版本以及编译工具的版本是需要的。

重要: 这里只能使用 com.android.application插件。如果使用 java插件将会报错。

目录结构

module/src/main下的目录结构,因为有时候很多人把 so放到 libs目录就会报错:

  • java/

  • res/

  • AndroidManifest.xml

  • assets/

  • aidl/

  • jniLibs/

  • jni/

  • rs/

配置目录结构

如果项目的结构不标准的时候,可能就需要去配置它。 Android插件使用了相似的语法,但是因为它有自己的 sourceSets,所以要在 android代码块中进行配置。下面就是一个从 Eclipse的老项目结构中配置主要代码并且将 androidTestsourceSet设置给 tests目录的例子:

 
   
   
 
  1. android {

  2.    sourceSets {

  3.        main {

  4.            manifest.srcFile 'AndroidManifest.xml'

  5.            java.srcDirs = ['src']

  6.            resources.srcDirs = ['src']

  7.            aidl.srcDirs = ['src']

  8.            renderscript.srcDirs = ['src']

  9.            res.srcDirs = ['res']

  10.            assets.srcDirs = ['assets']

  11.        }

  12.        androidTest.setRoot('tests')

  13.    }

  14. }

就像有些人就是要把 so放到 libs目录中(这类人有点犟),那就需要这样进行修改。
注意:因为在旧的项目结构中所有的源文件( Java, AIDLRenderScript)都放到同一个目录中,我们需要将 sourceSet中的这些新部件都设置给 src目录。

Build Tasks

对构建文件声明插件时通常或自动创建一些列的构建任务去执行。不管 Java插件还是 Android插件都是这样。 Android常规的任务如下:

  • assemble生成项目 output目录中的内容的任务。

  • check执行所有的检查的任务。

  • build执行 assemble和 check的任务。

  • clean清理项目 output目录的任务。

Android项目中至少会有两种 output输出:一个 debug apk和一个 release apk。他们都有自己的主任务来分别执行构建:

  • assemble

    • assembleDebug

    • assembleRelease

提示: Gradle支持通过命令行执行任务首字母缩写的方式。例如:
在没有其他任务符合 aR的前提下, gradle aRgradle assembleRelease是相同的。

最后,构建插件创建了为所有 build type(debug,release,test)类型安装和卸载的任务,只要他们能被安装(需要签名)。

  • installDebug

  • installRelease

  • uninstallAll

    • uninstallDebug

    • uninstallRelease

    • uninstallDebugAndroidTest

基本的 Build定制

Android插件提供了一些列的 DSL来让直接从构建系统中做大部分的定制。

Manifest整体部分

DSL提供了很多重要的配置 manifest文件的参数,例如:

  • minSdkVersion

  • targetSdkVersion

  • versionCode

  • versionName

  • applicationId

  • testApplicationId

  • testInstrumentationRunnder

Android Plugin DSL Reference提供了一个完整的构建参数列表。

把这些 manifest属性放到 build文件中的一个重要功能就是它可以被动态的设置。例如,可以通过读取一个文件或者其他逻辑来获取版本名称。

 
   
   
 
  1. def computeVersionName() {

  2.    ...

  3. }

  4. android {

  5.    compileSdkVersion 23

  6.    buildToolsVersion "23.0.1"

  7.    defaultConfig {

  8.        versionCode 12

  9.        versionName computeVersionName()

  10.        minSdkVersion 16

  11.        targetSdkVersion 23

  12.    }

  13. }

注意:不要使用可能与现有给定冲突的方法名。例如 defaultConfig{...}中使用 getVersionName()方法将会自动使用 defaultConfig.getVersionName()来带起自定义的方法。

BuildTypes

默认情况下 Android插件会自动将应用程序设置成有一个 debug版本和一个 release版本。
这就是通过调用 BuildType对象完成。默认情况下会创建两个实例,一个 debug实例和一个 release实例。 Android插件同样允许通过其他的 BuildTypes来定制其他的实例。这就是通过 buildTypes来设置的:

 
   
   
 
  1. android {

  2.    buildTypes {

  3.        debug {

  4.            applicationIdSuffix ".debug"

  5.        }

  6.        jnidebug {

  7.            initWith(buildTypes.debug)

  8.            applicationIdSuffix ".jnidebug"

  9.            jniDebuggable true

  10.        }

  11.    }

  12. }

上面的代码执行了以下操作:

  • 配置了默认 debug的 BuildType:

    • 设置了它的 applicationId。这样 debug模式就能与 release模式的 apk同时安装在同一手机上。

  • 创建了一个新的 jnidebug的 BuildType,并且把它设置为 debug的拷贝。

  • 通过允许 JNI组件的 debug和增加一个新的包名后缀来继续定制该 BuildType

不管使用 initWith()还是使用其他的代码块,创建一个新的 BuildTypes都是非常简单的在 buildTypes代码块中创建一个新的元素就可以了。

签名配置

为应用签名需要使用如下几个部分:

  • A keystore

  • A keystore password

  • A keyaliasname

  • A key password

  • Thestore type

默认情况下有一个 debug的配置,设置了一个 debugkeystore,有一个已知的密码。 debug keystore的位置是在 $HOME/.android/debug.keystore,如果没有的话他会被默认创建。 DebugBuildType会默认使用该 debug的签名设置。

当然也可以通过使用 DSL语法中的 signingconfigs部分来创建其他的配置来进行定制:

 
   
   
 
  1. android {

  2.    signingConfigs {

  3.        debug {

  4.            storeFile file("debug.keystore")

  5.        }

  6.        myConfig {

  7.            storeFile file("other.keystore")

  8.            storePassword "android"

  9.            keyAlias "androiddebugkey"

  10.            keyPassword "android"

  11.        }

  12.    }

  13.    buildTypes {

  14.        foo {

  15.            signingConfig signingConfigs.myConfig

  16.        }

  17.    }

  18. }

上面的设置将把 debug keystore的位置改为项目的根目录。同样也创建了一个新的签名配置,并且有一个新的 BuildType使用它。

Dependencies,AndroidLibrariesandMulti-project setup

Gradle项目可以依赖其他的外部二进制包、或者其他的 Gradle项目。

本地包

想要配置依赖一个外部 jar包,需要在 compile的配置中添加一个 dependency。下面的配置是添加了所有在 libs目录的 jar包:

 
   
   
 
  1. dependencies {

  2.    compile fileTree(dir: 'libs', include: ['*.jar'])

  3. }

  4. android {

  5.    ...

  6. }

注意: DSL元素中的 dependenciesGradleAPI中的标准元素。不属于 andorid元素。
compile配置是用来编译主应用的。它配置的所有部分都会被打包到 apk中。当然也有一些其他的配置:

  • compilemain application

  • androidTestCompiletest application

  • debugCompiledebugBuildType

  • releaseCompilereleaseBuildType

当然我们可以使用 compile<buildtype>.compile这两种配置。创建一个新的 BuildType通常会自动基于它的名字创建一个新的配置部分。这样在像 debug版本而 release版本不适用的一些特别的 library时非常有用。

远程仓库

Gradle只是使用 MavenIvy仓库。但是仓库必须要添加到列表中,并且必须声明所依赖仓库的 Maven或者 Ivy定义。

 
   
   
 
  1. repositories {

  2.     jcenter()

  3. }

  4. dependencies {

  5.    compile 'com.google.guava:guava:18.0'

  6. }

  7. android {

  8.    ...

  9. }

注意: jcenter()是指定仓库 URL的快捷设置。 Gradle支持远程和本地仓库。 注意: Gradle会直接识别所有的依赖关系。这就意味着如果一个依赖库自身又依赖别的库时,他们会被一起下下来。

本地 AAR
 
   
   
 
  1. dependencies {

  2.    compile(name:'本地aar库的名字,不用加后缀', ext:'aar')

  3. }

多项目设置

Gradle项目通常使用多项目设置来依赖其他的 gradle项目。例如:

  • MyProject/

    • lib1/

    • lib2/

    • app/

    • libraries/

Gradle会通过下面的名字来引用他们:
:app
:libraries:lib1
:libraries:lib2

每个项目都会有一个单独的 build文件,并且在项目的根目录还会有一个 setting.gradle文件:

  • MyProject/

    • lib1/

    • lib2/

    • build.gradle

    • build.gradle

    • build.gradle

    • settings.gradle

    • app/

    • libraries/

setting.gradle文件中的内容非常简单。它指定了哪个目录是 Gralde项目:

 
   
   
 
  1. include ':app', ':libraries:lib1', ':libraries:lib2'

app这个项目可能会依赖其他的 libraries,这样可以通过如下进行声明:

 
   
   
 
  1. dependencies {

  2.     compile project(':libraries:lib1')

  3. }

Library项目

上面用到了 :libraries:lib1:libraries:lib2可以是 Java项目, :app项目会使用他们俩的输出的 jar包。但是如果你需要使用 android资源等,这些 libraries就不能是普通的 Java项目了,他们必须是 AndroidLibrary项目。

创建一个 Library项目

Library项目和普通的 Android项目的区别比较少,由于 libraries的构建类型与应用程序的构建不同,所有它会使用一个别的构建插件。但是他们所使用的插件内部有很多相同的代码,他们都是由 com.android.tools.build.gradle这个 jar包提供的。

 
   
   
 
  1. buildscript {

  2.    repositories {

  3.        jcenter()

  4.    }

  5.    dependencies {

  6.        classpath 'com.android.tools.build:gradle:1.3.1'

  7.    }

  8. }

  9. apply plugin: 'com.android.library'

  10. android {

  11.    compileSdkVersion 23

  12.    buildToolsVersion "23.0.1"

  13. }

普通项目与 Library项目的区别

Library项目的主要输出我 .aar包。它结合了代码(例如 jar包或者本地 .so文件)和资源( manifest, res, assets)。每个 library也可以单独设置 BuildType等来指定生成不同版本的 aar

LintSupport

你可以通过指定对应的变量来设置 lint的运行。可以通过添加 lintOptions来进行配置:

 
   
   
 
  1. android {

  2.    lintOptions {

  3.        // turn off checking the given issue id's

  4.        disable 'TypographyFractions','TypographyQuotes'

  5.        // turn on the given issue id's

  6.        enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'

  7.        // check *only* the given issue id's

  8.        check 'NewApi', 'InlinedApi'

  9.    }

  10. }

Build变量

构建系统的一个目标就是能对同一个应用创建多个不同的版本。

Productflavors

一个 product flavor可以针对一个项目制定不同的构建版本。一个应用可以有多个不同的 falvors来改变生成的应用。
Productflavors是通过 DSL语法中的 productFlavors来声明的:

 
   
   
 
  1. android {

  2.    ....

  3.    productFlavors {

  4.        flavor1 {

  5.            ...

  6.        }

  7.        flavor2 {

  8.            ...

  9.        }

  10.    }

  11. }

BuildType+ProductFlavor=BuildVariant

像我们之前看到的,每个 BuildType都会生成一个 apk. ProductFlavors也是同样的:项目的输出僵尸所有 BuildTypesProductFlavors的结合。每种结合方式称之为 BuildVariant。例如,如果有 debugrelease版本的 BuildTypes,上面的例子就会生成4种 BuildVariants

  • Flavor1 - debug

  • Flavor1 - release

  • Flavor2 - debug

  • Flavor2 - release

没有配置 flavors的项目仍然有 BuildVariants,它只是用了一个默认的 flavor/config,没有名字,这导致 variants的列表和 BuildTypes的列表比较相同。

ProductFlavor配置
 
   
   
 
  1. android {

  2.    ...

  3.    defaultConfig {

  4.        minSdkVersion 8

  5.        versionCode 10

  6.    }

  7.    productFlavors {

  8.        flavor1 {

  9.            applicationId "com.example.flavor1"

  10.            versionCode 20

  11.         }

  12.         flavor2 {

  13.             applicationId "com.example.flavor2"

  14.             minSdkVersion 14

  15.         }

  16.    }

  17. }

注意 android.productFlavors.*对象 ProductFlavorandroid.defaultConfig是相同的类型。这就意味着他们有相同的属性。
defaultConfig为所有的 flavors提供了一些基本的配置,每个 flavor都已重写他们。在上面的例子中,这些配置有:

  • flavor1

    • applicationIdcom.example.flavor1

    • minSdkVersion: 8

    • versionCode: 20

  • flavor2

    • applicationIdcom.example.flavor2

    • minSdkVersion: 14

    • versionCode: 10

通常, BuildType配置会覆盖其他的配置。例如, BuildTypeapplicationIdSuffix会添加到 ProductFlavorapplicationId上。

最后,就像 BuildTypes一样, ProductFlavors也可以有他们自己的依赖关系。例如,如果有一个单独的 flavors会使用一些广告或者支付,那这个 flavors生成的 apk就会使用广告的依赖,而其他的 flavors就不需要使用。

 
   
   
 
  1. dependencies {

  2.    flavor1Compile "..."

  3. }

BuildConfig

在编译阶段, AndroidStudio会生成一个叫做 BuildConfig的类,该类包含了编译时使用的一些变量的值。你可以观看这些值来改变不同变量的行为:

 
   
   
 
  1. private void javaCode() {

  2.    if (BuildConfig.FLAVOR.equals("paidapp")) {

  3.        doIt();

  4.    else {

  5.        showOnlyInPaidAppDialog();

  6.    }

  7. }

下面是 BuildConfig中包含的一些值:

  • booleanDEBUG - ifthe buildisdebuggable

  • intVERSION_CODE

  • StringVERSION_NAME

  • StringAPPLICATION_ID

  • StringBUILD_TYPEBuildType的名字,例如 release

  • StringFLAVOR - flavor的名字,例如 flavor1

ProGuard配置

Android插件默认会使用 ProGuard插件,并且如果 BuildType中使用 ProGuardminifyEnabled属性开启的话,会默认创建对应的 task

 
   
   
 
  1. android {

  2.    buildTypes {

  3.        release {

  4.            minifyEnabled true

  5.            proguardFile getDefaultProguardFile('proguard-android.txt')

  6.        }

  7.    }

  8.    productFlavors {

  9.        flavor1 {

  10.        }

  11.        flavor2 {

  12.            proguardFile 'some-other-rules.txt'

  13.        }

  14.    }

  15. }

Tasks控制

基本的 Java项目有一系列的 tasks一起制作输出文件。
classes task就是编译 Java源码的任务。 我们可以在 build.gradle中通过使用 classes很简单的获取到它。就是 project.tasks.classes.

Android项目中,更多的编译 task,因为他们的名字通过 BuildTypesProductFlavors生成。

为了解决这个问题, android对象有两种属性:

  • applicationVariants - onlyforthe app plugin

  • libraryVariants - onlyforthe library plugin

  • testVariants - forboth plugins
    这些都会返回一个 ApplicationVariantLibraryVariantTestVariant的 DomainObjectCollection接口的实现类对象。
    DomainObjectCollection提供了直接获取或者很方便的间接获取所有对象的方法。

 
   
   
 
  1. android.applicationVariants.all { variant ->

  2.   ....

  3. }

设置编译语言版本

可以使用 compileOptions代码块来设置编译时使用的语言版本。默认是基于 compileSdkVersion的值。

 
   
   
 
  1. android {

  2.    compileOptions {

  3.        sourceCompatibility JavaVersion.VERSION_1_6

  4.        targetCompatibility JavaVersion.VERSION_1_6

  5.    }

  6. }

ResourceShrinking

Gradle构建系统支持资源清理:对构建的应用会自动移除无用的资源。不仅会移除项目中未使用的资源,而且还会移除项目所以来的类库中的资源。注意,资源清理只能在与代码清理结合使用(例如 ProGuad)。这就是为什么它能移除所依赖类库的无用资源。通常,类库中的所有资源都是使用的,只有类库中无用代码被移除后这些资源才会变成没有代码引用的无用资源。

 
   
   
 
  1. android {

  2.    ...

  3.    buildTypes {

  4.        release {

  5.            minifyEnabled true

  6.            shrinkResources true

  7.            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

  8.        }

  9.    }

  10. }



以上是关于Gradle&Maven-Gradle专题的主要内容,如果未能解决你的问题,请参考以下文章

Building Worlds In Unreal 学习笔记——15-19 高度图地形专题&地形自动材质专题

exgcd&&中国剩余定理专题练习

PHP & MySQL数据库专题 第三课 增删改查

Grails & gradle:插件管理

PHP & MySQL数据库专题 第二课 创建数据库 & 表

PHP & MySQL数据库专题 第十一课 索引