本文主要总结的内容如下:

  • Groovy介绍

  • 一、Gradle简介(定义与特性)

  • 二、Gradle使用

    • 1、Multi-Projects Build
    • 2、gradle命令
    • 3、gradle的工作流程
    • 4、Gradle编程模型
  • 三、Android中使用Gradle

    • 1、相关文件
    • 2、Android tasks
    • 3、相关配置
    • 4、Gradle模板举例

0、Groovy介绍:

Gradle 选择了GroovyGroovy基于Java并拓展了Java

Gradle选择了Groovy的原因:
Groovy基于Java并拓展了Java。 Java程序员可以无缝切换到使用Groovy开发程序。Groovy说白了就是把写Java程序变得像写脚本一样简单。写完就可以执行,Groovy内部会将其编译成Javaclass然后启动虚拟机来执行。

  • 1、定义:Groovy是在 java平台上的、 具有像PythonRubySmalltalk语言特性的灵活动态语言, Groovy保证了这些特性像 Java语法一样被 Java开发者使用。

  • 2、Groovy是一种动态语言。

  • 3、Groovy与Java的关系:
    当我执行Groovy脚本时,Groovy会先将其编译成Java类字节码,然后通过Jvm来执行这个Java类。


    Java、Groovy和Jvm的关系示意图
  • 4、特性:

    • Groovy注释标记和Java一样,支持//或者/**/
    • Groovy语句可以不用分号结尾。
    • Groovy中支持动态类型,即定义变量的时候可以不指定其类型。Groovy中,变量定义可以使用关键字def。注意,虽然def不是必须的,但是为了代码清晰,建议还是使用def关键字。
    • 函数定义时,参数的类型也可以不指定。
    • 除了变量定义可以不指定类型外,Groovy中函数的返回值也可以是无类型的
         //无类型的函数定义,必须使用def关键字   def  nonReturnTypeFunc(){       last_line   //最后一行代码的执行结果就是本函数的返回值   }   //如果指定了函数返回类型,则可不必加def关键字来定义函数   String getString(){      return"I am a string"   }

快速学习攻略:Groovy脚本基础全攻略

一、Gradle简介

1、定义

  • 1、Gradle是一个工具,同时它也是一个编程框架。

  • 2、Gradle中,每一个待编译的工程都叫一个Project
    每一个Project在构建的时候都包含一系列的Task
    比如一个Android APK的编译可能包含:Java源码编译Task、资源编译Task、JNI编译Task、lint检查Task、打包生成APK的Task、签名Task等。

  • 3、Gradle是一个框架,作为框架,它负责定义流程和规则。而具体的编译工作则是通过插件的方式来完成的。比如编译Java有Java插件,编译Groovy有Groovy插件,编译Android APP有Android APP插件,编译Android Library有Android Library插件。

2、特性:

  • 使用灵活的语言来写构建规则。
  • Gradle是一种DSL,即Domain Specific Language,领域相关语言。

二、Gradle使用

1、Multi-Projects Build

将多个Project进行统一编译,类似这种操作,在Gradle中,可以称之为Multi-Projects Build

1.1、使用方式:
  • 1、在工程根目录(如图中gradleProjects)下添加一个build.gradle文件(用于配置其他子Project的)

  • 2、在工程根目录(如图中gradleProjects)下添加一个settings.gradle文件(名称必须为settings.gradle用于告知Gradle包含多少个子Project)。

    Multi-Projects Build 文件夹示意图
1.2、.gradle 内容:
  • 1、build.gralde:
    为子Project添加一些属性。这个build.gradle有没有都无所属。

  • 2、settings.gradle

       #settings.gradle   include 'project1',           'project2',           'project3',           'project4'

2、gradle命令:

2.1、查看工程信息:
  • 命令:gradle projects
    在根目录(如gradleProjects)下打开终端,执行此命令
  • 结果:显示有多少个project
gradle projects命令
2.2、查看任务信息:
  • 命令:gradleproject-path:tasks
    在子目录(如project1)下打开终端,执行此命令。若不在子目录中则需要加上project-path
  • 结果:显示当前项目的任务信息
    由于我这个子目录下什么也没有,所以显示的信息是这个样子。
gradle:tasks命令
2.3、执行任务(task)
  • 命令:gradle task-name
    task-name为指定任务的名称,如clean清理任务
  • 示例:
    • gradle clean是执行清理任务,和make clean类似。
    • gradle properites 用来查看所有属性信息。

3、gradle的工作流程:

gradle工作流程

包含三个阶段:

  • 1、首先是初始化阶段(Initiliazation phase)。
    对我们前面的multi-project build而言,就是执行settings.gradle

  • 2、Configration阶段的目标是解析每个project中的build.gradle

    • 比如multi-project build例子中,解析每个子目录中的build.gradle。在这两个阶段之间,我们可以加一些定制化的Hook。这当然是通过API来添加的。

    • Configuration 阶段完了后,整个build的project以及内部的Task关系就确定了。一个Project包含很多Task,每个Task之间有依赖关系。Configuration会建立一个有向图来描述Task之间的依赖关系。所以,我们可以添加一个HOOK,即当Task关系图建立好后,执行一些操作。

  • 3、最后一个阶段就是执行任务了。
    你在gradle xxx中指定什么任务,gradle就会将这个xxx任务链上的所有任务全部按依赖顺序执行一遍!
    任务执行完后,我们还可以加Hook。

4、Gradle编程模型

Gradle基于Groovy,Groovy又基于Java。所以,Gradle执行的时候和Groovy一样,会把脚本转换成Java对象。

Gradle主要有三种对象,这三种对象和三种不同的脚本文件对应,在gradle执行的时候,会将脚本转换成对应的对端:

  • Gradle对象
    当我们执行gradle xxx或者什么的时候,gradle会从默认的配置脚本中构造出一个Gradle对象在整个执行过程中,只有这么一个对象。Gradle对象的数据类型就是Gradle。
    我们一般很少去定制这个默认的配置脚本。

  • Project对象:
    每一个build.gradle会转换成一个Project对象

  • Settings对象:
    每一个settings.gradle都会转换成一个Settings对象

各种类型Gradle对应的对象类型:

脚本类型 关联对象类型
Build script Project
Init script Gradle
Settings script Settings
4.1、Gradle对象:

gradle对象的属性如图,其中的几个属性说明如下:

  • hashCode()
    在settings.gradle和build.gradle中,gradle实例对象的hashCode是一样的
  • HomeDir
    是指在哪个目录存储的gradle可执行程序
  • User Home Dir
    gradle自己设置的目录,里边存储了一些配置文件,以及编译过程中的缓存文件,生成的类文件,编译中依赖的插件等等。
Gradle对象属性
4.2、Project对象:
  • 1、每一个build.gradle文件都会转换成一个Project对象。在Gradle术语中,Project对象对应的是BuildScript

  • 2、Project包含若干Tasks。由于Project对应具体的工程,所以需要为Project加载所需要的插件,比如为Java工程加载Java插件。其实,一个Project包含多少Task往往是插件决定的。

  • 3、一个项目在构建时都具备如下流程:

    • 为当前项目创建一个Settings类型的实例。
    • 如果当前项目存在settings.gradle文件,则通过该文件配置刚才创建的Settings实例。
    • 通过Settings实例的配置创建项目层级结构的Project对象实例。
    • 最后通过上面创建的项目层级结构Project对象实例去执行每个Project对应的build.gradle 脚本。
  • 4、在Project中,需要:

    • 加载插件(调用apply函数):
       //二进制插件(如jar包) //Android中的build.gradle apply plugin: 'com.android.library'    <==如果是编译Library,则加载此插件 apply plugin: 'com.android.application'  <==如果是编译Android APP,则加载此插件  //加载一个gradle文件  apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
    • 不同插件有不同的配置。在Project中配置后,插件就知道从何处读取源文件
    • 设置属性:
      单个脚本,不需要考虑属性的跨脚本传播。
      extra property(额外属性):通过ext前缀标示是一个额外属性。定义好之后,后面的存取就不需要ext前缀了。ext属性支持Project和Gradle对象。即Project和Gradle对象都可以设置ext属性:
          //第一次定义或者设置它的时候需要ext前缀    gradle.ext.api =properties.getProperty('sdk.api')    println gradle.api  //再次存取api的时候,就不需要ext前缀了

三、Android中的Gradle

Android自己定义了好多Script Block。Android定义的DSL参考文档在
https://developer.android.com/tools/building/plugin-for-gradle.html下载。

Android的DSL参考信息

1、相关文件

  • Android中gradle项目基本的目录结构:
     demoApp    |-- build.gradle    |-- settings.gradle    |-- app        |-- build.gradle    |-- gradlew    |-- gradlew.bat    |-- gradle        |-- wrapper            |-- gradle-wrapper.jar            |-- gradle-wrapper.properties    |-- gradle.properties    |-- local.properties
1.1、local.properties

对于Android来说,local.properties 是必须的,下面两个配置sdk.dir和ndk.dir是Android Gradle必须要指定的。

   #设置sdk目录   sdk.dir=xxx   #设置ndk目录   ndk.dir=yyy
1.2、项目根目录(顶层)的build.gradle

一般情况下,这个build.gradle 是做一些全局配置,其配置最终会被应用到所有项目中。它典型的配置如下:

   apply from: 'dependencies.gradle'      buildscript {       repositories {           jcenter()           mavenCentral()       }       dependencies {           classpath 'com.android.tools.build:gradle:3.2.1'       }   }      allprojects {       repositories {           jcenter()           google()       }   }      task clean(type: Delete) {       delete rootProject.buildDir   }
  • buildscript:定义了 Android 编译工具的类路径。repositories 中的 jCentermavenCentral` 是两个仓库。

  • allprojects:中定义的属性会被应用到所有 module 中,但是为了保证每个项目的独立性,我们一般不会在这里面操作太多共有的东西。(一般外部依赖库都在其中,gradle会通过查找在这里配置的仓库来比编译指定的依赖库?)

1.3、每个子项目中的build.gradle

针对每个module 的配置,如果其build.gradle中定义的选项和顶层build.gradle定义的相同,则顶层中的配置会被覆盖。典型的配置内容如下:

      apply plugin: 'com.android.application'            android {          compileSdkVersion 28          buildToolsVersion "28.0.3"                defaultConfig {              applicationId "com.demo.testapp"              minSdkVersion 14              targetSdkVersion 28                    versionCode 1.1.1              versionName "111"          }                signingConfigs {              debug {                  storeFile file("../debug.jks")                        storePassword "123456"                  keyAlias "haha"                  keyPassword "123456"              }                    release {                  storeFile file("../release.jks")                        storePassword "123456"                  keyAlias "haha"                  keyPassword "123456"              }          }                buildTypes {              debug {                  minifyEnabled false      //是否混淆                  shrinkResources false    //去除没有用到的资源文件              }                    release {                  minifyEnabled true                  shrinkResources true                  proguardFiles getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro"                  signingConfig signingConfigs.release              }          }                repositories {              //添加aar              flatDir {                  dirs 'libs'              }          }            }            dependencies {          api fileTree(include: ['*.jar'], dir: 'libs')          api "com.android.support:appcompat-v7:27.1.1"      }
  • apply plugin:gradle插件,作为Android 的应用程序,这一步是必须的,因为plugin中提供了Android 编译、测试、打包等等的所有task。

  • android:关于android 的所有特殊配置都在这个代码块中,这就是由上面声明的 plugin 提供的。

    • defaultConfig:程序的默认配置;这里配置的相关属性会覆盖AndroidManifest.xml 中定义的属性(如versionName)
    • applicationId:定义了APP的包名,不同于AndroidManifest.xml中的package属性。
  • buildTypes:定义了编译类型,针对每个类型我们可以有不同的编译配置,不同的编译配置对应的有不同的编译命令。默认的有debugrelease 的类型。

  • dependencies:gradle 的依赖配置。它定义了当前项目需要依赖的其他库。

1.4、Gradle Wrapper

gradle wrapper 是针对gradle新版本对旧版本的向后兼容性问题而使用的。

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

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

  • gradle wrapper目录结构:
     demoApp    |-- gradlew    |-- gradlew.bat    |-- gradle        |-- wrapper            |-- gradle-wrapper.jar            |-- gradle-wrapper.properties

2、Android tasks

2.1、基本的tasks:
  • assemble:对buildType 下的所有配置类型生成相应的apk包
  • clean:移除所有编译输出的文件,如apk
  • check:执行lint检测编译
  • build:同时执行assemblecheck

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

2.2、新增task:
  • install,会将编译后的apk 安装到连接的设备。

3、相关配置

3.1、BuildConfig

这个类是由gradle根据配置文件生成的,通过配置一些key-value 的键值对,可以用BuildConfig获取相应的字段。例如:

    //module下的build.gradle    buildTypes {        debug {            //配置网络请求根地址            buildConfigField 'String', 'API_URL', '"http://test.com/api/debug/"'            //配置app名称            resValue "string", "app_name", "测试版"        }        release {            //配置网络请求根地址            buildConfigField 'String', 'API_URL', '"http://test.com/api/release/"'            //配置app名称            resValue "string", "app_name", "上线版"        }    }

在使用时,只需要调用BuildConfig.API_URL,就能获得当前环境(debug或release)下的值。
而用resValue配置的,则不需要再strings.xml中配置相应名称的值,否则会报错。

3.2、Repositories

repositories中配置的是代码仓库。在dependencies 中配置的一些依赖库都是从这里下载的。
Gradle 支持三种类型的仓库:MavenIvy和一些静态文件或者文件夹。在编译的执行阶段,gradle 将会从仓库中取出对应需要的依赖文件,当然,gradle 本地也会有自己的缓存,不会每次都去取这些依赖。

  • gradle 支持多种 Maven 仓库,一般常用的是jCenter

     //项目根目录下的build.gradle repositories {     jcenter()     google() }
  • 有一些项目,可能是一些公司私有的仓库中的,这时候需要手动加入仓库连接,而有的需要用户名和密码,

     //项目根目录下的build.gradle repositories {    maven {        url 'https://jitpack.io'        credentials {           username 'xxx'           password 'yyy'        }    }  }
  • 可以使用相对路径配置本地仓库,通过配置项目中存在的静态文件夹作为本地仓库:

       //module下的build.gradle   android {     ......     repositories {        flatDir {            dirs 'libs'        }      }   }
3.3、Dependencies

依赖库的配置。

  • File dependencies
    通过files()方法可以添加文件依赖,如果有很多jar文件,我们也可以通过fileTree()方法添加一个文件夹,除此之外,我们还可以通过通配符的方式添加,如下:
   //module下的build.gradle   dependencies {       api fileTree(include: ['*.jar'], dir: 'libs')   }
  • aar dependencies
    可以将项目打包成aar 文件,通过文件的形式来引用:
   //module下的build.gradle   //其中的aarname是打包的aar文件的名称,后面的ext是固定的   dependencies {       api(name: 'aarname', ext: 'aar')   }
3.4、Source sets

封装所有变体的源集配置。

  • 1、Native libraries
    配置本地 .so库。在配置文件中做如下配置,然后在对应位置建立文件夹,加入对应平台的.so文件。
   //方式一:    android {        sourceSets {            main {                jniLibs.srcDirs = ['libs', , 'src/main/jni']            }        }    }    //方式二    android {        sourceSets.main {            jni.srcDirs 'libs'        }    }
jni目录示意图
  • 2、配置源集:
        sourceSets {        main {            //更改Java源的目录。默认目录是:'src/main/java'。            java.srcDirs = ['other/java']            // 默认目录是'src/main/res'            res.srcDirs = [ 'other/res1', 'other/res2' ]            //设置清单。默认目录是:src/main/AndroidManifest.xml            manifest.srcFile 'other/AndroidManifest.xml'            ...        }        //创建其他块以配置其他源集。        androidTest {            setRoot 'src/tests'            ...        }    }
    • main中的res.srcDirs如果列出多个目录,Gradle将使用它们来收集源。由于Gradle为这些目录提供了相同的优先级,如果在多个目录中定义相同的资源,则在合并资源时会出现错误。

    • 对于每个源集,只能指定一个AndroidManifest.xml。

    • 如果源集的所有文件都位于单个根目录下,则可以使用setRoot属性指定该目录。收集源集的源时,Gradle仅在相对于您指定的根目录的位置中查找。例如,在将配置应用于androidTest源集之后,Gradle仅在src/tests/java/ 目录中查找Java源。

3.5、Product flavors:

关于构建不同的Product flavors,可以参考如下:
Build Variants
技术:Android打包签名总结

4、Gradle模板举例

  • 4.1、Project的build.gradle

       // Top-level build file where you can add configuration options common to all sub-projects/modules.   //全局引入gradle文件   apply from: 'dependencies.gradle'      //gradle脚本执行所需依赖,包含依赖仓库和插件   buildscript {          //配置远程仓库       repositories {           //从Android Studio3.0后新增了google()配置,可以引用google上的开源项目           google()           //一个类似于github的代码托管仓库,声明了jcenter()配置,可以轻松引用 jcenter上的开源项目           jcenter()              //本地仓库           mavenLocal()           //maven中央仓库           mavenCentral()           //指定maven仓库           maven { url "https://jitpack.io" }           maven { url 'https://maven.google.com' }       }          //配置插件       dependencies {           //此处是android的插件gradle,gradle是一个强大的项目构建工具           classpath 'com.android.tools.build:gradle:3.2.1'           //其他插件,这里是数据库greendao的插件           classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'       }   }      //项目本身需要的依赖,比如项目所需的maven库   allprojects {       repositories {           jcenter()           google()           maven { url 'https://jitpack.io' }           maven { url 'https://maven.google.com' }       }   }      //清除任务   task clean(type: Delete) {       delete rootProject.buildDir   }
  • 4.2、Module的build.gradle

       //app应用插件,声明为Android应用程序   apply plugin: 'com.android.application' //表示是一个应用程序模块,直接运行   //apply plugin: 'com.android.library'   //表示是一个库模块,被其他module依赖      apply plugin: 'walle'   //其他插件,这里是打包插件      //定义变量   def versionConfigs = rootProject.extensions.getByName("ext")      android {       //编译时用的Android版本       compileSdkVersion versionConfigs.androidCompileSdkVersion       //构建工具的版本       buildToolsVersion versionConfigs.androidBuildToolsVersion          //默认配置,会被下面的相同的配置覆盖       defaultConfig {           //项目包名,唯一标识,和AndroidManifest.xml中的package(Java文件包名)不同           applicationId "com.example.app"           //程序最低兼容的运行版本,低于此版本无法安装           minSdkVersion versionConfigs.androidMinSdkVersion           //项目的目标版本           targetSdkVersion versionConfigs.androidTargetSdkVersion              //版本号           versionCode VERSION_CODE as int           //版本名称,给用户看的           versionName VERSION_NAME              //支持multidex   //        multiDexEnabled true              //表明要使用AndroidJUnitRunner进行单元测试           testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"       }          //程序在编译的时候会检查lint,有任何错误提示会停止build,我们可以关闭这个开关       lintOptions {           //打包release版本的时候进行检测           checkReleaseBuilds false           //即使报错也不会停止打包           abortOnError false           //屏蔽translate引起的warning           disable "MissingTranslation"       }          //自动化打包配置,可以自定义配置多种打包配置       signingConfigs {           //测试配置           debug {               //debug签名文件路径               storeFile file("../debug.jks")                  //签名相关信息,配置在了gradle.properties中了               storePassword SIGNINGCONFIGS_PSW               keyAlias SIGNINGCONFIGS_KEYALIAS               keyPassword SIGNINGCONFIGS_PSW           }              //上线配置           release {               //release签名文件路径               storeFile file("../release.jks")                  //签名相关信息,配置在了gradle.properties中了               storePassword SIGNINGCONFIGS_PSW               keyAlias SIGNINGCONFIGS_KEYALIAS               keyPassword SIGNINGCONFIGS_PSW           }       }          //构建类型,可自定义多种类型       buildTypes {           debug {               minifyEnabled false      //是否混淆               shrinkResources false    //去除没有用到的资源文件           }              release {               minifyEnabled true               shrinkResources true               proguardFiles getDefaultProguardFile('proguard-android.txt'), "$rootDir/ModuleLibs/config/proguard-rules.pro"               signingConfig signingConfigs.release           }       }          repositories {           //添加本地aar目录           flatDir {               dirs 'libs'           }       }          //配置源集       sourceSets {//目录指向配置           main {               jniLibs.srcDirs = ['libs']//指定lib库目录           }       }      }      //依赖   dependencies {       //本地文件依赖       api fileTree(include: ['*.jar'], dir: 'libs')          //测试用例库       testImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {           exclude group: 'com.android.support', module: 'support-annotations'       })          //依赖corelib的module       api project(':corelib')              //定义外部变量的引用       def andlibs = rootProject.ext.andlibs       def libs = rootProject.ext.libs       api andlibs.appcompat_v7   }

相关链接:
Android Plugin DSL Reference
Gradle Android插件用户指南翻译

深入理解Android之Gradle
史上最全Android build.gradle配置详解
Gradle 完整指南(Android)
Gradle 提速:每天为你省下一杯喝咖啡的时间

更多相关文章

  1. 下载和编译Android源码问题集(持续更新)
  2. 有关JDK,tomcat,android sdk+MyEclipse+adt 配置
  3. android中SQLite使用查看
  4. Android(安卓)MediaScanner:(四)MediaScanner之scanSingleFile
  5. Android(安卓)studio 使用ndk开发JNI
  6. Android(安卓)SugarORM(1)
  7. 第五章 Android加载PDF文件的使用
  8. 1.1 如何配置Android的开发环境步骤
  9. 第二次WIN7下配置Android模拟器环境手记

随机推荐

  1. 安卓开发基础介绍
  2. android notification通知栏及8.0适配
  3. 做嵌入式的必须学Android吗
  4. Android(安卓)如何让EditText不自动获取
  5. android与html5的交互——数据库操作,UI操
  6. 修正Android摄像头API
  7. Android的多任务运行机制
  8. Android(安卓)Studio安装配置(详细版)
  9. 通过Ant将android project打包成apk并安
  10. 如何发布你的Android应用程序