本文参考:
gradle是用于构建项目的,在安卓项目中,gradle构建主要是针对.gradle文件,一个安卓项目中的.gradle文件有三种:
- 根目录下的build.gradle:进行全局配置
- 每一个子Moudle下的build.gradle:执行各个构建Task
- settings.gradle:通过include函数将子Moudle的Project包含进来;
Groovy:
gradle是基于groovy语言的,groovy语言同java一样,会编译为字节码交给jvm执行,Groovy基于Java并拓展了Java,所以可以直接使用java中的规范,下面介绍一些groovy的扩展:
1. 变量定义:
def variable1 = 1 //可以不使用分号结尾
def varable2 = "I ama person"
def int x = 1 //变量定义时,也可以直接指定类型
2. 方法定义:
函数定义时,参数的类型也可以不指定。比如
String testFunction(arg1,arg2){ //无需指定参数类型
...
}
除了变量定义可以不指定类型外,Groovy中函数的返回值也可以是无类型的。
//无类型的函数定义,必须使用def关键字
def nonReturnTypeFunc(){
last_line //最后一行代码的执行结果就是本函数的返回值
}
3. 闭包:
英文叫Closure,这是groovy中的一个数据类型,表示一段可以执行的代码,长这样:
def aClosure = {//闭包是一段代码,所以需要用花括号括起来..
println"this is code" //这是代码,最后一句是返回值,
//也可以使用return,和Groovy中普通函数一样
}
Closure闭包的注意点:
- 闭包中有一个隐式参数it,类似java的this
- 如果方法的最后一个参数式Closure类型,可以省略()
Gradle工作流程:
在了解Gradle的构建流程前,需要知道两个概念,Project,Task,每一个待编译的工程都叫做Project,每一个Project都包含了多个Task,比如Android APK的编译,可能包括Java源代码编译,资源编译,打包,签名;这些编译任务都是通过一个一个的Task完成的;
-
Initialization:
初始化阶段,Gradle 将会确定哪些项目将参与构建,并为每个项目创建一个 Project 对象实例。对于 Android 项目来说即为执行 setting.gradle 文件;
一般setting.gradle都是这样的:通过include函数将所有的Project包含进来
include ':app', ':a', ':b'
-
Configuration:
配置阶段,会解读每一个build.gradle文件,分析里面的task,然后将这些task形成一个有向图,表示task的依赖关系
task testBoth {
println '我会在 Configuration 和 Execution 阶段都会执行'
doFirst {
println '我仅会在 testBoth 的 Execution 阶段执行'
}
doLast {
println '我仅会在 testBoth 的 Execution 阶段执行'
}
}
写在Task闭包的任务会在Configuration阶段运行,而doFirst,doLast会在Execution阶段运行;
切记大部分的内容是写在 doLast{} 或 doFirst{} 闭包中,因为写在如果写在 task 闭包中的话,会在 Configuration 阶段也被执行。
-
Execution:
task 的执行阶段。首先执行 doFirst {} 闭包中的内容,最后执行 doLast {} 闭包中的内容。
我们可以hook默认的构建过程,加入一些自定义的操作;
Project:
从上面我们可以知道每一个build.gradle都对应了一个Project对象,Project又包含了多个Task,每一个Task对应了一个构建任务;
@HasInternalProtocol
public interface Project extends Comparable, ExtensionAware, PluginAware {}
Project本质是一个Java类,可以通过Java提供的方法配置Project中的Task,因为每一个build.gradle都对应了一个具体的工程,所以需要为它指定一个插件,java工程添加java插件,安卓工程添加安卓插件:
apply plugin: 'com.android.library'
apply plugin: 'com.android.application'
使用的是apply函数
,这个函数是PluginAware类下的函数
/**
* Applies a plugin or script, using the given options provided as a map. Does nothing if the plugin has already been applied.
* <p>
* The given map is applied as a series of method calls to a newly created {@link ObjectConfigurationAction}.
* That is, each key in the map is expected to be the name of a method {@link ObjectConfigurationAction} and the value to be compatible arguments to that method.
*
* <p>The following options are available:</p>
*
* <ul><li>{@code from}: A script to apply. Accepts any path supported by {@link org.gradle.api.Project#uri(Object)}.</li>
*
* <li>{@code plugin}: The id or implementation class of the plugin to apply.</li>
*
* <li>{@code to}: The target delegate object or objects. The default is this plugin aware object. Use this to configure objects other than this object.</li></ul>
*
* @param options the options to use to configure and {@link ObjectConfigurationAction} before “executing” it
*/
void apply(Map<String, ?> options);
Task:
task是gradle中的一种数据类型,它代表了需要执行的工作,可以使用task函数
创建一个Task任务;
task cleanAuraBundleFile << {
def providedDir = new File("$project.projectDir/auraBundles/provided-bundles")
providedDir.deleteDir()
}
<<符号是doLast的缩写
[图片上传失败...(image-88ea71-1602754294365)]
.gradle文件中包含了多个 Script Block
,让我们配置相关信息,不同的SB需要配置不同的东西:
根build.gradle:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.1"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
上面的buildscript,repository,dependencies,就是SB,他们分别配置不同的信息;他们可以在Gradle DSL 学习中找到每一个解释,比如allprojects是用于配置当前 project 和所有子 project 的,该方法将会在这些 project 中执行给定的闭包;
子build.gradle:
apply plugin: 'com.android.application' // 引入插件
android { // android的编译,增加了一种新类型的ScriptBlock-->android
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.example.myapplication"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
//implementation表示编译和运行时候需要的jar包,fileTree是一个函数
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
子项目的.gradle文件中的SB就可以在这里找到解释Android Plugin DSL 学习
自定义Gradle Plugin
1. 在Android项目下新建一个Android library:
2. 将Module里的内容删除,只保留build.gradle文件和src/main目录,同时移除build.gradle文件里的内容,将里面内容修改为:
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies{
// gradle sdk
compile gradleApi()
// groovy sdk
compile localGroovy()
compile 'com.android.tools.build:gradle:1.5.0'
}
repositories{
mavenCentral()
}
3 将Module里的目录修改为以下格式:
在main目录下新建groovy目录,这时候groovy文件夹会被Android识别为groovy源码目录。除了在main目录下新建groovy目录外,你还要在main目录下新建resources目录,同理resources目录会被自动识别为资源文件夹。在groovy目录下新建项目包名,就像Java包名那样。resources目录下新建文件夹META-INF,META-INF文件夹下新建gradle-plugins文件夹。这样,就完成了gradle 插件的项目的整体搭建。
4 在groovy目录下创建groovy文件
import org.gradle.api.Plugin
import org.gradle.api.Project
public class PluginImpl implements Plugin<Project>{
void apply(Project project){
System.out.println("========================");
System.out.println("hello gradle plugin!");
System.out.println("========================");
}
}
5 声明插件名称:
在resources/META-INF/gradle-plugins目录下新建一个properties文件,注意该文件的命名就是你使用插件的名字,这里命名为sayhello.properties,文件内容引入插件的类:
implementation-class=com.myplugin.PluginImpl
那么你在其他build.gradle文件中使用自定义的插件时候则需写成:
apply plugin: 'sayhello'
6 发布插件
在Model的build.gradle文件下插入一个发布的task
uploadArchives {
repositories {
mavenDeployer {
pom.groupId = 'com.myplugins'
pom.artifactId = 'myplugins'
pom.version = 1.3
// maven本地仓库的目录
repository(url: uri('../packplugin'))
}
}
}
sync后在右侧的Task中心可以看到这个Task:
点击上传插件后就可以在项目中看到这个插件了:
7 在项目中引入插件
注意com后面的包名和插件名需要和upload的一致;