【android 应用】关于gradle的一份学习总结报告,请查收。

一、了解gradle

1.概述

1.1 gradle是什么

gradle是一款基于JVM的专注于灵活性和性能的开源构建工具。
gradle用的是一种基于 Groovy 的领域特定语言(DSL,Demain Specific Language)来声明项目设置,摒弃了 XML(如 ANT 和 Maven)的各种繁琐配置。

1.2 作用

1.3 为什么用gradle?

附上:Gradle官网:https://gradle.org

2.Android gradle plugin

Android gradle plugin是Gradle插件,也就是AndroidStudio用于开发Android项目的gradle插件。
gradle是构建工具,可以构建java应用,web应用。而gradle plugin只是google用来构建android应用的一个android studio插件。

3.gradle wrapper

每个基于gradle构建的工程都有一个gradle本地代理,叫做 gradle wrappe。在 /gradle/wrapper/gralde-wrapper.properties 目录中声明了指向目录和版本。

每一个Wrapper都会绑定到一个特定版本的Gradle,当用户第一次执行如下的命令时,Wrapper会自动地下载并安装对应版本的Gradle,方便用户构建项目。

 

二、Groovy基本语法

1、基础语法

1、语句可以不以分号结尾

2、函数调用可以不需要参数括号

println 'hello world'

3、动态类型

Groovy 定义变量的方式和 Java 是类似的,区别在于 Groovy 提供了def关键字供使用,它可以省略变量类型的定义,根据变量的值进行类型推导。

如:
def a = 123
def b = 'b'
def c = true
boolean d = false
int e = 123

4、函数写法

Groovy 方法的默认访问修饰符是public,方法的返回类型可以不需要声明,但需添加def关键字。有返回值的方法return可以被省略,默认返回最后一行代码的运行结果,如果使用了return关键字则返回指定的返回值。

例:
String method1() {
   return 'hello'
}
assert method1() == 'hello';
def method2() {
   return 'hello'
}
assert method2() == 'hello';
def method3() {
   'hello'
}
assert method3() == 'hello';
Groovy 方法的参数类型可以被省略,默认为Object类型。
例:
def add(int a, int b) {
   return a + b
}
//与上面的等价
def add(a, b) {
   a + b
}

Groovy 方法的其他特性与Java一样,比如支持重载、不定长参数(…)等。

5、不需要main函数

在Java中要输出“hello world”需要像下面这样,创建一个类,然后创建一个main方法。

public class Hello {
   public static void main(String[] args) {
       System.out.println("hello world");
   }
}

在Groovy中,这些都可以省略,实例如下:

例:在文本中写如下groovy语句

println 'Groovy world!'

上面我们写的groovy文件编译后的class其实是Java类,该类从Script类派生而来(查阅API);可以发现,每个脚本都会生成一个static main方法,我们执行groovy脚本的实质其实是执行的这个Java类的main方法,脚本源码里所有代码都被放到了run方法中,脚本中定义的方法(该例暂无)都会被定义在Main类中。如下:

import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
   def run() {
       println 'Groovy world!'
   }
   static void main(String[] args) {          
       InvokerHelper.runScript(Main, args)    
   }
}

6、Groovy快速入门博客

https://www.jianshu.com/p/e8dec95c4326

2、闭包

闭包其实就是一段代码块。在gradle中,我们主要是把闭包当参数来使用

例如1:
//定义一个闭包
def b1 = {
   println “hello b1”
}
//定义一个方法,方法里面需要闭包类型参数
def method1 (Closure closure) {
   closure()
}
//调用方法
method1(b1)
结果:输出hello b1

例如2:
//定义一个闭包,带参数
def b2 = {
   v->
       println "hello ${v}"
}
//定义一个方法,方法里面需要闭包类型参数
def method2 (Closure closure) {
   closure("xiaoma")
}
//调用方法
method2(b2)
结果:输出hello xiaoma

例如3:
//多个参数以逗号分隔,参数类型和方法一样可以显式声明也可省略。
def closure = { String x, int y ->                                
   println "hey {y}"
}

3、元编程

groovy运行时类方法调用流程:

在java中,如果对象调用了一个类中没有定义过的方法时,连编译都编译不过,但是在groovy中,情况则不同(可以编译通过),根据图中流程可以知道,运行期间,当对象调用了一个类中没有的方法时,会依次调用metaClass中的同名方法,类中的methodMissing(String name, Object args)方法,类中的invokeMethod(String name, Object args)方法,执行到其中一个便停止后续方法查找调用。

三、Gradle项目编译

1.Android Gradle项目结构

含有两个子模块(app和remoteDiagnosisLibrary)的项目结构如下:

1.1gradle.properties

可以在 gradle.properties 文件中配置一些变量,这些变量在这个工程下的所有module的build.gradle文件里都可以使用。这样就可以把一些共用的变量放到这里,这样后面修改的时候就可以只修改这个变量,不用各个模块都要修改了。
上图项目结构中的gradle.properties如下:

1.2settings.gradle

Gradle试图找到一个设置(settings.gradle)。为此,运行时将目录树的层次结构遍历到根目录。一旦找到设置文件,算法就停止搜索。
总是添加一个设置到构建的根目录,以避免初始性能影响。
上图项目结构中的settings.gradle如下:

1.3build.gradle

配置脚本文件名默认是不变的build.gradle,每一个project(模块)对应一个build.gradle。

2.编译执行流程

一次Gradle的工作流分为3大部分:

第一:初始化。
Gradle支持单个和多个项目的构建。在初始化阶段,Gradle确定哪些项目将参与构建,并为每个项目创建一个项目实例。
第二:配置。
在此阶段,将配置项目对象。作为构建的一部分的所有项目的构建脚本都被执行。
第三:执行。
Gradle确定在配置阶段创建和配置的要执行的任务的子集。子集由传递给gradle命令和当前目录的任务名参数决定。然后Gradle执行每一个选择的任务。

实例1:创建task

task haha{
    println("hahaha")
    doLast{
        println("ccccc")
    }
    doFirst{
        println("aaaaa")
    }
    doLast{
        println("bbbbbb")
    }
    println("endendend")
}

注:
doFirst:将给定添加Action到此任务的操作列表的开头。
doLast:将给定添加Action到此任务的操作列表的最后。

执行haha task,结果如下

Configure project:打印表明是第二阶段:配置阶段
Task:haha打印表明是第三阶段:执行阶段

这个地方特别理解一下:

1、dolast方法创建的任务,在配置阶段只是创建执行的任务,真正执行是在执行阶段。所以hahaha打印在configure阶段,cccccc打印在task阶段

2、执行阶段task的顺序

没有顺序之前是按照字母顺序排列,可以通过依赖方法(dependsOn)、doFirst、doLast调整顺序

 

3.模块Project

1、每个项目都会有自己的gradle领域,配置脚本文件名默认是不变的build.gradle
2、Project之间如果出现父子关系,只有根Project才会有setting.gradle配置文件,该配置文件的作用是声明其包含的子项目。
3、Project代表一个项目,在jvm中的一个实例。Build.gradle中无主的方法都可以在project中找到

4.任务Task介绍

1.概述

task,如其名:任务,gradle就是由一个一个任务来完成的。他其实也是一个类,有自己的属性,也可以"继承",甚至他还有自己的生命周期。Task是构建中的最小执行单元。
task的基类是DefaultTask ,我们也可以自定义一个task,必须继承DefaultTask,如下:

class MyTask extends DefaultTask {
   String message = 'This is MyTask'
   // @TaskAction 表示该Task要执行的动作,即在调用该Task时,hello()方法将被执行
   @TaskAction
   def hello(){
       println "Hello gradle. $message"
   }
}

2.默认Task

Gradle 允许在脚本中定义一个或多个默认任务.

2.1 添加默认任务的方法

在build.gradle中调用defaultTasks方法,将要设置成默认的task方法传入进去。

2.2 实例
build.gradle

defaultTasks 'clean', 'run'
task clean << {
   println 'Default Cleaning!'
}
task run << {
   println 'Default Running!'
}
task other << {
   println "I'm not a default task!"
}

gradle -q 命令的输出:

gradle -q
Default Cleaning!
Default Running!

结果等价于执行编译命令gradle clean run。

在一个多项目构建中, 每一个子项目都可以有它特别的默认任务. 如果一个子项目没有特别的默认任务, 父项目的默认任务将会被执行.

3.自定义Task

如下:vpsclient项目的gradle.build中创建了一个clean任务。

4.Gradle、Settings、Project、Task之间关系

Gradle

表示对Gradle的调用。

Settings

声明实例化和配置Project要参与构建的实例的层次结构所需的配置。
对应的文件是setting.gradle。

Project

Project代表一个项目,在jvm中的一个实例。该接口是用于与构建文件中的Gradle交互的主要API。从中Project,您可以通过编程方式访问Gradle的所有功能。
Project和build.gradle 文件之间存在一对一的关系。

Task

Task代表构建的一项基本工作,例如编译类或生成javadoc。

四者之间的联系:
1、执行gradle命令时,会创建一个gradle对象。
2、在构建初始化过程中,Gradle为每个要参与构建的项目装配一个项目对象,具体如下:

为构建创建Settings实例。
Settings。gradle脚本,如果存在,针对设置对象来配置它。
使用已配置的Settings对象创建Project实例的层次结构。
最后,Project通过build.gradle针对项目执行其文件(如果存在)来评估每个文件。这些项目以广度顺序进行评估,因此在其子项目之前先对其进行评估。可以通过调用Project.evaluationDependsOnChildren()或添加使用的显式评估依赖项来覆盖此顺序Project.evaluationDependsOn(java.lang.String)。

3、Project本质上是Task对象的集合。每个Task都属于一个Project。

四、Gradle配置

1、Build.gradle配置文件Demo

重要的属性:

android属性

设置编译android项目的参数,构建android项目的所有配置都写在这里。
实例说明:

android {
   // 编译SDK的版本
   compileSdkVersion 22
   // build tools的版本
   buildToolsVersion "23.0.1"
   //aapt配置
   aaptOptions {
       //不用压缩的文件
       noCompress 'pak', 'dat', 'bin', 'notice'
       //打包时候要忽略的文件
       ignoreAssetsPattern "!.svn:!.git"
       //分包
       multiDexEnabled true
       //--extra-packages是为资源文件设置别名:意思是通过该应用包名+R,com.android.test1.R和com.android.test2.R都可以访问到资源
       additionalParameters '--extra-packages', 'com.android.test1','--extra-packages','com.android.test2'
   }
   //默认配置
   defaultConfig {
       //应用的包名
       applicationId "com.example.heqiang.androiddemo"
       minSdkVersion 21
       targetSdkVersion 22
       versionCode 1
       versionName "1.0"
   }
   //编译配置
   compileOptions {
       // java版本
       sourceCompatibility JavaVersion.VERSION_1_7
       targetCompatibility JavaVersion.VERSION_1_7
   }
   //源文件目录设置
   sourceSets {
       main {
            //jni lib的位置
            jniLibs.srcDirs = jniLibs.srcDirs << 'src/jniLibs'
            //定义多个资源文件夹,这种情况下,两个资源文件夹具有相同优先级,即如果一个资源在两个文件夹都声明了,合并会报错。
            res.srcDirs = ['src/main/res', 'src/main/res2']
            //指定多个源文件目录
            java.srcDirs = ['src/main/java', 'src/main/aidl']
       }
   }
   //签名配置
   signingConfigs {
       debug {
           keyAlias 'androiddebugkey'
           keyPassword 'android'
           storeFile file('keystore/debug.keystore')
           storePassword 'android'
       }
   }
   buildTypes {
       //release版本配置
       release {
           debuggable false
           // 是否进行混淆
           minifyEnabled true
           //去除没有用到的资源文件,要求minifyEnabled为true才生效
           shrinkResources true
           // 混淆文件的位置
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
           signingConfig signingConfigs.debug
           //ndk的一些相关配置,也可以放到defaultConfig里面。
           //指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,arm-v8之类的so会被过滤掉)
           ndk {
               abiFilter "armeabi"
           }
       }
       //debug版本配置
       debug {
           debuggable true
           // 是否进行混淆
           minifyEnabled false
           //去除没有用到的资源文件,要求minifyEnabled为true才生效
           shrinkResources true
           // 混淆文件的位置
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
           signingConfig signingConfigs.debug
           //ndk的一些相关配置,也可以放到defaultConfig里面。
           //指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,arm-v8之类的so会被过滤掉)
           ndk {
               abiFilter "armeabi"
           }
       }
   }
   // lint配置
   lintOptions {
     //移除lint检查的error
     abortOnError false
     //禁止掉某些lint检查
     disable 'NewApi'
   }
}

除了上面写的,在android{}块中可以包含以下直接配置项:
productFlavors{ } 产品风格配置,ProductFlavor类型
testOptions{ } 测试配置,TestOptions类型
dexOptions{ } dex配置,DexOptions类型
packagingOptions{ } PackagingOptions类型
jacoco{ } JacocoExtension类型。用于设定 jacoco版本
splits{ } Splits类型。

dependencies属性

gradle中所有的jar包的座标都放在这个属性内,每个jar包都包含三个基本元素(group,name,version)。

2、Gradle构建语言帮助文档地址

Gradle配置Build.gradle脚本语言帮助文档地址:

https://docs.gradle.org/current/dsl/

3、修改成国内源(阿里源)

在 project 的 build.gradle中修改如下:

allprojects {
   repositories {
       //jcenter()
       maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
   }
}

然后点击 gradle rync 即可。

4、自定义gradle插件

4.1 二进制插件

apply plugin: 'xxx'   //声明引用插件的类型

如腾讯shadow中buildScripts/gradle/maven.gradle:

4.2 应用脚本插件

apply from:'xxx'   //表示引用其他的配置文件

如腾讯shadow中gradle.build:

就是引用了buildScripts/gradle/下面的两个配置文件

五、Gradle自定义构建

1、构建的变体

1.1 概述

构建变体是构建版本和生产版本的结合体。当你创建了一个构建版本或者生产版本,同样的,新的变体也会被创建。

像下图便有这么多的变体:

1.2 创建构建变体

flavorDimensions "channel","money"
android {
   productFlavors {
      vivo {
           dimension "channel"
           applicationId "vivo"
           versionCode 1
           minSdkVersion 15
       }
       oppo {
           dimension "channel"
           applicationId "oppo"
           versionCode 2
           minSdkVersion 15
       }
       free {
           dimension "money"
           resValue "color", "colorfree", "#ff8888"
       }
       vip {
           dimension "money"
           resValue "color", "colorfree", "#ff0000"
       }
   }
}

2、自定义构建流程

2.1在某任务之前执行

Task diyTask = project.task('diyTask') {
   doLast {
       Utils.println("diy task run")
   }
}
project.tasks.whenTaskAdded { Task theTask ->
   if (theTask.name == 'assembleDebug') {
       theTask.dependsOn(diyTask)
       theTask.mustRunAfter(diyTask)            // diyTask在assembleRelease之前执行
   }
}

2.1在某任务之后执行

Task diyTask = project.task('diyTask') {
   doLast {
       Utils.println("diy task run")
   }
}
project.tasks.whenTaskAdded { Task theTask ->
   if (theTask.name == 'assembleRelease') {
       theTask.dependsOn(diyTask)            // diyTask在assembleRelease之后执行
   }
}

 

六、Gradle命令

1、任务查询和运行命令

查看任务

./gradlew tasks

查看所有任务 包括缓存任务等

./gradlew tasks --all

对某个module [moduleName] 的某个任务[TaskName] 运行

./gradlew :moduleName:taskName

2、快速构建命令

查看构建版本

./gradlew -v

清除build文件夹

./gradlew clean

检查依赖并编译打包

./gradlew build

编译并安装debug包

./gradlew installDebug

编译并打印日志

./gradlew build --info

译并输出性能报告,性能报告一般在 构建工程根目录 build/reports/profile

./gradlew build --profile

调试模式构建并打印堆栈日志

./gradlew build --info --debug --stacktrace

强制更新最新依赖,清除构建并构建

./gradlew clean build --refresh-dependencies

3、指定构建目标命令

编译并打Debug包

./gradlew assembleDebug

这个是简写 assembleDebug

./gradlew aD

编译并打Release的包

./gradlew assembleRelease

这个是简写 assembleRelease

./gradlew aR

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章