语法基础——Gradle语法基础"/>
语法基础——Gradle语法基础
生命周期
Gradle的构建依次会执行下面的三个生命周期
- 初始化阶段(Initialization):解析整个工程中的所有Project,构建出所有的project对象
- 配置阶段(Configuration):解析所有的projects对象中的task,构建好所有task的拓扑图
- 执行阶段(Execution):执行具体的task及其依赖task
生命周期监听
在项目的build.gradle中,监听配置阶段和执行阶段的生命周期
this.gradle.beforeProject {println "配置阶段开始之前(一)"
}this.beforeEvaluate {println "配置阶段开始之前(二)"
}this.gradle.afterProject {println "配置阶段执行完毕(一)"
}this.afterEvaluate {println "配置阶段执行完毕(二)"
}this.gradle.buildFinished {println "执行阶段执行完毕"
}
在项目的settings.gradle中,监听初始化阶段的生命周期,直接增加输出即可
include ':app'
println "初始化阶段开始"
执行clean
命令后,可以在控制台看到生命周期的执行顺序
Executing tasks: [clean]初始化阶段开始
Configuration on demand is an incubating feature.
配置阶段执行完毕(一)
配置阶段执行完毕(二)
配置阶段开始之前(一)
配置阶段执行完毕(一)
:clean
:app:cleanBUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
执行阶段执行完毕
Project对象
项目中的工程或Module都可以看成Project对象,根工程称为Root Project
,Module称为子Project
- 如果在工程中或Module中存在build.gradle文件,那么它就是Project对象
- 如果在工程中或Module中不存在build.gradle文件,那么它就是个文件夹
对于子Project来说,一个子Project对应一个输出,输出类型是根据build.gradle文件来确定的
- 如果build.gradle定义application类型,则输出为apk
- 如果build.gradle定义library类型,则输出为aar
Project相关Api
1、获取所有的Project
def getProjects(){this.getAllprojects().eachWithIndex { Project project ,int index ->if(index == 0){println "Root Project :${project.name}"}else{println "+--- Project :${project.name}"}}
}
2、获取所有的子Project
def getProjects(){this.getSubprojects().eachWithIndex { Project project ,int index ->println "+--- Project :${project.name}"}
}
3、获取父Project
def getProjects(){def name = this.getParent().nameprintln "parent project: ${name}"
}
4、获取根Project
def getProjects(){def name = this.getRootProject().nameprintln "parent project: ${name}"
}
5、获取指定名字的Project
project('app') {apply plugin: 'com.android.application'group 'com.hensen'version '1.0.0'dependencies {}android {}
}
6、统一配置所有的Project
allprojects {group 'com.hensen'version '1.0.0'
}
7、统一配置所有的子Project
subprojects { Project project ->if(project.plugins.hasPlugin('com.android.library')){apply from: '../publishToMaven.gradle'}
}
Project属性Api
1、在根工程或gradle文件中定义全局扩展属性
//在根工程或gradle文件中定义扩展属性
ext {android = [compileSdkVersion : 25,buildToolsVersion : '25.0.0',versionCode : 1,versionName : '1.0.0']
}
//如果在gradle文件中定义扩展属性,需要在子工程引入该gradle文件,然后在子工程使用扩展属性
apply from: '../common.gradle'
android {compileSdkVersion rootProject.ext.androidpileSdkVersionbuildToolsVersion rootProject.ext.android.buildToolsVersiondefaultConfig {versionCode rootProject.ext.android.versionCodeversionName rootProject.ext.android.versionName......}
}
2、在gradle.properties中定义全局扩展属性
在gradle.properties定义全局扩展属性,应该注意命名不能和系统定义的属性重名,否则会报出找不到扩展属性
//在gradle.properties文件中定义全局扩展属性
isIncludeTestModule = false
mCompileSdkVersion = 25//在settings.gradle中使用扩展属性
if(hasProperty('isIncludeTestModule') ? isIncludeTestModule.toBoolean() : false){include ':Test'
}
//在build.gradle中使用扩展属性
android {compileSdkVersion mCompileSdkVersion.toInteger()......
}
文件Api
1、获取工程相关的文件
println getRootDir().absolutePath
println getBuildDir().absolutePath
println getProjectDir().absolutePath
2、获取文件内容
getContent('build.gradle')def getContent(String path){try{def file = file(path)return file.text}catch(GradleException e){println 'file not found'}return null
}
3、文件拷贝
copy {from file('build/outputs/apk/app-debug.apk')into getRootProject().getBuildDir()
}
4、文件夹拷贝
copy {from file('build/outputs/apk/')into getRootProject().getBuildDir().path + '/apk/'exclude {} //可以对不需要拷贝的文件进行移除rename {} //可以对文件进行重命名
}
5、文件树遍历
fileTree('build/outputs/apk/') { FileTree fileTree ->fileTree.visit { FileTreeElement element ->println element.fileprintln element.file.name}
}
依赖第三方Api
1、根工程的第三方依赖
buildscript {//配置工程的仓库地址repositories {google()jcenter()mavenCentral()mavenLocal()maven { name 'netWork' url 'http://localhost:8080/nexus/repositories'credentials{username = 'Hensen'password = '123456'}}}//配置工程的插件依赖地址dependencies {classpath 'com.android.tools.build:gradle:3.0.1'}
}
2、子工程的第三方依赖
dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])compile ('com.android.support:appcompat-v7:26.1.0') {exclude module: 'support-v4'exclude group: 'com.android.support'exclude group: 'com.android.support', module: 'support-v4'transitive false //禁止传递依赖}provided 'com.android.support:support-v4:26.1.0'
}
概念梳理
- 传递依赖:A依赖B,B依赖C,如果允许传递依赖,那么A可以使用C的内容,否则为禁止传递依赖
- compile:参与编译时期和参与打包过程
- provided:参与编译时期,但不参与打包过程
provided应用场景
- 当前依赖的库只适用于编译时期生成代码的工具库
- 当前依赖的库已经存在于根工程的依赖,在子工程中只参与编译
外部命令Api
1、调用系统指令
task(name: 'apkcopy') {doLast {def srcPath = this.buildDir.path + '/outputs/apk'def destPath = './target/apk'def command = "mv -f ${srcPath} ${destPath}"exec {try {executable 'bash'args '-c', commandprintln 'this command exec success'}catch(GradleException e){println 'this command exec error'}}}
}
2、调用脚本
task stopTomcat(type:Exec) {//dirworkingDir '../tomcat/bin'//windowscommandLine 'cmd', '/c', 'stop.bat'//linuxcommandLine './stop.sh'
}
task对象
1、定义
由于task运行于配置阶段中,因此在gradle文件中,只要执行其中一个task,则其他task都会执行一遍
//第一种定义方式
task helloword(group: 'hensen',description :'hello'){println "Hello Word"
}
//第二种定义方式
this.tasks.create(name: 'helloword'){setGroup('hensen')setDescription('hello')println "Hello Word"
}
2、时序
//第一种定义方式
task helloword(group: 'hensen',description :'hello'){println "Hello Word"doFirst {println "doFirst"}doLast {println "doLast"}
}
//第二种定义方式
helloword.doFirst {println "doFirst"
}
//第三种定义方式
helloword << {println "doLast"
}
三种定义方式中,第二种定义方式会比第一种定义方式先执行
- doFirst:task配置阶段时运行
- doLast:task执行阶段时运行
- <<:doLast的简写,等同于doLast
3、计算build执行时长
gradle build执行的时长即task执行阶段的时长
def startTime,endTime
this.afterEvaluate { Project project ->def prebuild = project.tasks.getByName('preBuild')prebuild.doFirst {startTime = System.currentTimeMillis()}def build = project.tasks.getByName('build')build.doLast {endTime = System.currentTimeMillis()println "the build time is : ${endTime - startTime}"}
}
4、依赖关系
task与task之间的依赖
task taskA {doLast {println "taskA run"}
}
task taskB {doLast {println "taskB run"}
}
task taskC(dependsOn: [taskA, taskB]) {doLast {println "taskC run"}
}//执行taskC后的输出结果
taskA run
taskB run
taskC run
task与lib之间的依赖
task taskC {dependsOn this.tasks.findAll { task ->return task.name.startsWith('lib')}doLast {println "taskC run"}
}
task lib1 << {println 'lib1'}
task lib2 << {println 'lib2'}
task lib3 << {println 'lib3'}//执行taskC后的输出结果
lib1
lib2
lib3
taskC run
5、输入输出
通过指定输入的属性和输出的文件,在构建完成后自动将信息解析成xml存放在releases.xml文件中,作为版本说明的文本
ext {versionName = rootProject.ext.android.versionNameversionCode = rootProject.ext.android.versionCodeversionInfo = 'App 2.0.0版本 上线啦'destFile = file('releases.xml')if (destFile != null && !destFile.exists()) {destFile.createNewFile()}
}task writeTask {inputs.property('versionCode', this.versionCode)inputs.property('versionName', this.versionName)inputs.property('versionInfo', this.versionInfo)outputs.file this.destFiledoLast { //将输入的内容写入到输出文件中去def data = inputs.getProperties()File file = outputs.getFiles().getSingleFile()def versionMsg = new VersionMsg(data) //将实体对象写入到xml文件中def sw = new StringWriter()def xmlBuilder = new MarkupBuilder(sw)if (file.text != null && file.text.size() <= 0) { //没有内容xmlBuilder.releases {release {versionCode(versionMsg.versionCode)versionName(versionMsg.versionName)versionInfo(versionMsg.versionInfo)}} //直接写入file.withWriter { writer -> writer.append(sw.toString())}} else { //已有其它版本内容xmlBuilder.release {versionCode(versionMsg.versionCode)versionName(versionMsg.versionName)versionInfo(versionMsg.versionInfo)} //插入到最后一行前面def lines = file.readLines()def lengths = lines.size() - 1file.withWriter { writer ->lines.eachWithIndex { line, index ->if (index != lengths) {writer.append(line + '\r\n')} else if (index == lengths) {writer.append('\r\r\n' + sw.toString() + '\r\n')writer.append(lines.get(lengths))}}}}}
}task readTask { //指定输入文件为上一个task的输出inputs.file this.destFiledoLast { //读取输入文件的内容并显示def file = inputs.files.singleFileprintln file.text}
}class VersionMsg {String versionCodeString versionNameString versionInfo
}this.project.afterEvaluate { project ->def buildTask = project.tasks.getByName('build')buildTask.doLast {writeTask.execute()}
}
6、执行顺序
无论三个task的执行顺序是怎么样,它们都会按照指定的顺序taskA taskB taskC
执行
task taskA {doLast {println "taskA run"}
}
task taskB {mustRunAfter taskAdoLast {println "taskB run"}
}
task taskC() {mustRunAfter taskBdoLast {println "taskC run"}
}
Setting对象
Setting对象对应项目中的工程的settings.gradle文件,它是gradle的初始化阶段时运行的文件
SourceSets对象
sourceSets可以指定当前的工程使用哪套资源配置来进行不同模版的切换,比如经常用到的是闪屏界面的特效切换等
sourceSets {main {java.srcDir = ['src']java.excludes = ['androidTest/**','test/**']mainfest.srcFile 'AndroidManifest.xml'jniLibs.srcDirs = ['libs']if (app_type == "1") {res.srcDirs = ['res','res_a']assets.srcDirs = ['assets','assets_a']} else if (app_type == "2"){res.srcDirs = ['res','res_b']assets.srcDirs = ['assets','assets_b']}}
}
Variants相关Api
Variants指的是多渠道打包出来的apk的一种统称
this.afterEvaluate {this.android.applicationVariants.all { variant ->//获取Variants相关属性def name = variant.namedef baseName = variant.baseNamedef buildType = variant.buildTypedef signingConfig = variant. signingConfigdef versionName = variant.versionNamedef verionCode = variant.versionCodeprintln "name: ${name} , baseName: ${baseName}"//修改variant的apk名字def output = variant.outputs.first()def apkName = "app-${variant.baseName}-${variant.versionName}.apk"output.outputFile = new File(output.outputFile.parent,apkName)//修改variant的taskdef checkTask = variant.checkManifestcheckTask.doFirst {...... }}
}//输出结果
name: appDebug , baseName: app-debug
name: baiduDebug , baseName: baidu-debug
自定义Plugin
自定义Plugin是在原有的工程项目中增加一个新的Module作为Plugin,自定义Plugin的目录结构和正常的Project目录结构有很大区别,而且自定义Plugin的目录结构需要按照规定的命名规则和存放位置才能生效,自定义Plugin分为三步骤:
- 自定义Plugin
- 自定义Extension
- 自定义Task
下图是自定义Plugin的目录结构,其中有两个主要的目录
- groovy:编写groovy脚本的目录,创建的文件都必须以groovy为后缀名
- resources:必须创建
META-INF/gradle-plugins
的目录和properties
文件,其命名会用在project中的apply plugin
语句中
一、自定义Plugin
1、创建MineSdkPlugin.groovy
,实现Plugin<Project>
package com.hensen.pluginimport org.gradle.api.Plugin
import org.gradle.api.Projectclass MineSdkPlugin implements Plugin<Project> {@Overridevoid apply(Project project) {println "Hello Gradle Plugin"}
}
2、编写build.gradle
,创建uploadArchives
上传Plugin到本地仓库
apply plugin: 'groovy'
apply plugin: 'maven'group "com.hensen.plugin"
version "1.0.0"dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])implementation gradleApi()implementation localGroovy()implementation 'com.android.tools.build:gradle:3.0.1'
}sourceSets {main {groovy {srcDir 'src/main/groovy'}resources {srcDir 'src/main/resources'}}
}uploadArchives {repositories {mavenDeployer {repository(url: uri('../repo')) //定义本地maven仓库的地址}}
}sourceCompatibility = "1.7"
targetCompatibility = "1.7"
3、编写com.hensen.plugin.properties
,指定Plugin的路径
implementation-class=com.hensen.plugin.MineSdkPlugin
4、执行gradle project右边栏的upload/uploadArchives
,在本地仓库生成自定义Plugin信息
二、自定义Extension
1、创建MineExtension
,提供Plugin的参数配置项
public class MineExtension {def appIdString appVersionboolean autoBackUpMineExtension() {appId = ""appVersion = ""autoBackUp = false}
}
2、在MineSdkPlugin
中,创建Extension
class MineSdkPlugin implements Plugin<Project> {@Overridevoid apply(Project project) {println "Hello Gradle Plugin"project.extensions.create("MineSdkExtension", MineExtension)}
}
3、执行gradle project右边栏的upload/uploadArchives
,在本地仓库更新自定义Plugin信息
三、自定义Task
1、创建MineTask
,继承DefaultTask
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskActionclass MineTask extends DefaultTask {public MineTask(){group = "mine"description = "MineSdkTask"}/*** 执行在gradle的执行阶段*/@TaskActionvoid doAction() {printInfo()}private void printInfo() {println project.extensions.MineSdkExtension.appIdprintln project.extensions.MineSdkExtension.appVersionprintln project.extensions.MineSdkExtension.autoBackUp}
}
2、在MineSdkPlugin
中,创建Task
class MineSdkPlugin implements Plugin<Project> {@Overridevoid apply(Project project) {println "Hello Gradle Plugin"project.extensions.create("MineSdkExtension", MineExtension)project.tasks.create("MineSdkTask", MineTask)}
}
3、执行gradle project右边栏的upload/uploadArchives
,在本地仓库更新自定义Plugin信息
四、使用自定义Plugin
1、在根build.gradle
引入maven地址和classpath
buildscript {repositories {maven {url uri('./repo')}jcenter()}dependencies {classpath 'com.android.tools.build:gradle:3.0.1'//取名规则 group:module:versionclasspath 'com.hensen.plugin:mine-sdk-plugin:1.0.0'}
}allprojects {repositories {maven {url uri('./repo')}jcenter()}
}
2、在project的build.gradle
中引入自定义Plugin,然后使用MineSdkExtension
apply plugin: 'com.android.application'
apply plugin: 'com.hensen.plugin' //引入自定义Pluginandroid {......
}dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])
}//使用自定义Extension
MineSdkExtension {appId "10010"appVersion "1.0.1"autoBackUp true
}
3、执行gradle project右边栏的mine/MineSdkTask
,在gradle console
就能看到输出结果
Executing tasks: [MineSdkTask]Configuration on demand is an incubating feature.
Hello Gradle Plugin
:app:MineSdkTask
10010
1.0.1
trueBUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
更多推荐
语法基础——Gradle语法基础
发布评论