安卓Gradle的学习与理解

来源:互联网 发布:豆瓣电影数据库 编辑:程序博客网 时间:2024/05/21 15:45

理解基本的Gradle

如果你想创建一个Android project基于gradle,那么你必须写一个构建脚本,这个文件通常称之为build.grade,你可能已经觉察到了,当我们查看这一脚本,gradle会为我们提供很多默认的配置以及通常的默认值,而这极大的简化了我们的工作,例如ant和maven,使用他们的时候,我们需要编写大量的配置文件,而这很恶心。而gradle得默认配置,如果你需要使用自己的配置,完全可以简单的去重写他们就好。

Gradle脚本不是像传统的xml文件那样,而是一种基于Groovy的动态DSL,而Groovy语言是一种基于jvm的动态语言。

你完全不用担心,你在使用gradle的时候,还需要去学习Groovy语言,该语言很容易阅读,并且如果你已经学习过java的话,学习Groovy将不会是难事,如果你想开始创建自己的tasks和插件,那么你最好对Groovy有一个较深的理解,然而由于其基于jvm,所以你完全可能通过纯正的java代码或者其他任何基于jvm的语言去开发你自己的插件,关于插件开发,我们后续将会有相关介绍。

Project和tasks

在grade中的两大重要的概念,分别是project和tasks。每一次构建都是有至少一个project来完成,所以Android studio中的project和Gradle中的project不是一个概念。每个project有至少一个tasks。每一个build.grade文件代表着一个project。tasks在build.gradle中定义。当初始化构建进程,gradle会基于build文件,集合所有的project和tasks,一个tasks包含了一系列动作,然后它们将会按照顺序执行,一个动作就是一段被执行的代码,很像Java中的方法。

构建的生命周期

一旦一个tasks被执行,那么它不会再次执行了,不包含依赖的Tasks总是优先执行,一次构建将会经历下列三个阶段:

  1. 初始化阶段:project实例在这儿创建,如果有多个模块,即有多个build.gradle文件,多个project将会被创建。

  2. 配置阶段:在该阶段,build.gradle脚本将会执行,为每个project创建和配置所有的tasks。

  3. 执行阶段:这一阶段,gradle会决定哪一个tasks会被执行,哪一个tasks会被执行完全依赖开始构建时传入的参数和当前所在的文件夹位置有关。


Gradle Files

  • 项目project的build.gradle:文件的配置最终会被应用到所有项目中。它典型的配置如下:
buildscript {    repositories {        jcenter()    }    dependencies {        classpath 'com.android.tools.build:gradle:1.2.3'    }}allprojects{    repositories{        jcenter()    }}
  • buildscript:定义了 Android 编译工具的类路径。repositories中,jCenter是一个著名的 Maven 仓库。
  • allprojects:中定义的属性会被应用到所有 moudle 中,但是为了保证每个项目的独立性,我们一般不会在这里面操作太多共有的东西。

  • 每个项目单独的 build.gradle:针对每个moudle 的配置,如果这里的定义的选项和顶层build.gradle定义的相同,后者会被覆盖。典型的 配置内容如下:


    • apply plugin:第一行代码应用了Android 程序的gradle插件,作为Android 的应用程序,这一步是必须的,因为plugin中提供了Android 编译、测试、打包等等的所有task。
    • android:这是编译文件中最大的代码块,关于android 的所有特殊配置都在这里,这就是又我们前面的声明的 plugin 提供的。
      • defaultConfig就是程序的默认配置,注意,如果在AndroidMainfest.xml里面定义了与这里相同的属性,会以这里的为主。
      • 这里最有必要要说明的是applicationId的选项:在我们曾经定义的AndroidManifest.xml中,那里定义的包名有两个用途:一个是作为程序的唯一识别ID,防止在同一手机装两个一样的程序;另一个就是作为我们R资源类的包名。在以前我们修改这个ID会导致所有用引用R资源类的地方都要修改。但是现在我们如果修改applicationId只会修改当前程序的ID,而不会去修改源码中资源文件的引用。
    • buildTypes:定义了编译类型,针对每个类型我们可以有不同的编译配置,不同的编译配置对应的有不同的编译命令。默认的有debug、release 的类型。
    • dependencies:是属于gradle 的依赖配置。它定义了当前项目需要依赖的其他库。

    Gradle Wrapper

    Gradle 不断的在发展,新的版本难免会对以往的项目有一些向后兼容性的问题,这个时候,gradle wrapper就应运而生了。

    gradlw wrapper 包含一些脚本文件和针对不同系统下面的运行文件。wrapper 有版本区分,但是并不需要你手动去下载,当你运行脚本的时候,如果本地没有会自动下载对应版本文件。

    在不同操作系统下面执行的脚本不同,在 Mac 系统下执行./gradlew ...,在windows 下执行gradle.bat进行编译。

    如果你是直接从eclipse 中的项目转换过来的,程序并不会自动创建wrapper脚本,我们需要手动创建。在命令行输入以下命令即可

    gradle wrapper --gradle-version 2.4

    它会创建如下目录结构:


wrapper 就是我们使用命令行编译的开始。下面我们看看 wrapper 有什么样的作用。

Gradle basics

Gradle 会根据build 文件的配置生成不同的task,我们可以直接单独执行每一个task。通过./gradlew tasks列出所有task。如果通过同时还想列出每个task 对应依赖的其他task,可以使用./gradlew tasks -all

其实每当我们在Android Studio点击 build,rebuild,clean菜单的时候,执行的就是一些gradle task.

Android tasks

有四个基本的 task, Android 继承他们分别进行了自己的实现:

  • assemble:对所有的 buildType 生成 apk 包。
  • clean:移除所有的编译输出文件,比如apk
  • check:执行lint检测编译。
  • build:同时执行assemblecheck命令

这些都是基本的命令,在实际项目中会根据不同的配置,会对这些task 设置不同的依赖。比如 默认的 assmeble 会依赖 assembleDebug 和assembleRelease,如果直接执行assmeble,最后会编译debug,和release 的所有版本出来。如果我们只需要编译debug 版本,我们可以运行assembleDebug

除此之外还有一些常用的新增的其他命令,比如 install命令,会将编译后的apk 安装到连接的设备。

我们运行的许多命令除了会输出到命令行,还会在build文件夹下生产一份运行报告。比如check命令会生成lint-results.html.build/outputs中。

Configuration

BuildConfig

这个类相信大家都不会陌生,我们最常用的用法就是通过BuildConfig.DEBUG来判断当前的版本是否是debug版本,如果是就会输出一些只有在 debug 环境下才会执行的操作。 这个类就是由gradle 根据 配置文件生成的。为什么gradle 可以直接生成一个Java 字节码类,这就得益于我们的 gradle 的编写语言是Groovy, Groovy 是一种 JVM 语言,JVM 语言的特征就是,虽然编写的语法不一样,但是他们最终都会编程 JVM 字节码文件。同是JVM 语言的还有 Scala,Kotlin 等等。

这个功能非常强大,我们可以通过在这里设置一些key-value对,这些key-value 对在不同编译类型的 apk 下的值不同,比如我们可以为debug 和release 两种环境定义不同的服务器。比如:


Repositories

Repositories 就是代码仓库,这个相信大家都知道,我们平时的添加的一些 dependency 就是从这里下载的,Gradle 支持三种类型的仓库:Maven,Ivy和一些静态文件或者文件夹。在编译的执行阶段,gradle 将会从仓库中取出对应需要的依赖文件,当然,gradle 本地也会有自己的缓存,不会每次都去取这些依赖。

gradle 支持多种 Maven 仓库,一般我们就是用共有的jCenter就可以了。
有一些项目,可能是一些公司私有的仓库中的,这时候我们需要手动加入仓库连接:


Dependencies

我们在引用库的时候,每个库名称包含三个元素:组名:库名称:版本号,如下:

dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    compile 'com.android.support:appcompat-v7:25.0.0'    compile 'com.android.support:support-v4:25.0.0'    compile 'com.android.support:recyclerview-v7:25.0.+'    compile 'com.android.support:design:25.0.0'    compile 'com.makeramen:roundedimageview:2.2.1'    compile 'com.github.bumptech.glide:glide:4.0.0'    compile 'com.facebook.android:facebook-android-sdk:4.24.0'    compile 'com.google.code.gson:gson:2.6.1'    compile 'com.github.chrisbanes:PhotoView:1.3.0'    compile 'com.google.android.gms:play-services-maps:9.6.1'    compile 'com.google.android.gms:play-services-analytics:9.6.1'    compile 'org.greenrobot:eventbus:3.0.0'    compile 'com.squareup.retrofit2:retrofit:2.1.0'    // retrofit 框架    compile 'com.squareup.retrofit2:converter-gson:2.0.2'    compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'    compile 'com.baoyz.swipemenulistview:library:1.3.0'    apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'    compile 'io.reactivex.rxjava2:rxjava:2.0.5'    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'    compile project(':ptr-lib')    compile project(':banner')    compile project(path: ':guideview')}

Build Variants

在开发中我们可能会有这样的需求:

  • 我们需要在debug 和 release 两种情况下配置不同的服务器地址;
  • 当打市场渠道包的时候,我们可能需要打免费版、收费版,或者内部版、外部版的程序。
  • 渠道首发包通常需要要求在欢迎页添加渠道的logo。等等
  • 为了让市场版和debug版同时存在与一个手机,我们需要编译的时候自动给debug版本不一样的包名。

这些需求都需要在编译的时候动态根据当前的编译类型输出不同样式的apk文件。这时候就是我们的buildType大展身手的时候了。

Build Type

android 默认的带有Debug和Release两种编译类型。比如我们现在有一个新的statging的编译类型

buildTypes {    release {        buildConfigField "boolean", "LOG_DEBUG", "false"        buildConfigField "String", "KEY", "\"__PAZB_ANDOIRD__\""        minifyEnabled true        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        signingConfig signingConfigs.releass        // 移除无用的resource文件        shrinkResources true    }    debug {        // 显示Log        buildConfigField "boolean", "LOG_DEBUG", "true"        buildConfigField "String", "KEY", "\"__PAZB_ANDOIRD__\""        minifyEnabled false        zipAlignEnabled false        shrinkResources false        signingConfig signingConfigs.debug    }}

Source sets

每当创建一个新的build type 的时候,gradle 默认都会创建一个新的source set。我们可以建立与main文件夹同级的文件夹,根据编译类型的不同我们可以选择对某些源码直接进行替换。



Product flavors

前面我们都是针对同一份源码编译同一个程序的不同类型,如果我们需要针对同一份源码编译不同的程序(包名也不同),比如 免费版和收费版。我们就需要Product flavors

注意,Product flavors和Build Type是不一样的,而且他们的属性也不一样。所有的 product flavor 版本和defaultConfig 共享所有属性!

像Build type 一样,product flavor 也可以有自己的source set文件夹。除此之外,product flavor 和 build type 可以结合,他们的文件夹里面的文件优先级甚至高于 单独的built type 和product flavor 文件夹的优先级。如果你想对于 blue类型的release 版本有不同的图标,我们可以建立一个文件夹叫blueRelease,注意,这个顺序不能错,一定是 flavor+buildType 的形式。

更复杂的情况下,我们可能需要多个product 的维度进行组合,比如我想要 color 和 price 两个维度去构建程序。这时候我们就需要使用flavorDimensions


这就是一个Gradle的简单介绍,不对的地方多担待希望一起学习!!!!!

原创粉丝点击