1. 为什么不用Groovy编写Gradle脚本
动态语言 VS 静态语言
静态语言编译器有代码提示,编译的代码更健壮
静态语言 是指在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。例如:C++、Java、Delphi、C#、 kotlin 等。
动态语言 是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。例如:Python、Ruby、Perl,groovy, javascript等。
所以我把build.gradle 该成
kts
后缀之后, 再添加代码库时,我们会发现,有提示了
2. Gradle 基础知识
Gradle 本身的领域对象主要有Project和Task
Project 为Task 提供了执行的容器和上下文
1 project
看源码发现,project(工程)是 org.gradle.api 定义的一个接口,gradle之所以能够工作,是因为在gradle编写的代码,会以任务的方式插入到project里面,project会执行我们编写的任务(task)。project提供了任务执行的环境和上下文。 安卓程序员来看,像是一个上下文(Context)的功能。
2 task
Task(任务)就是执行在 project里面的,是一个一个的小模块。个人理解像Kotlin里面的扩展函数。
3 HelloWorld
- 我们把 build.gradle.kts 里面默认生成的代码全删掉,添加下面的代码
task("HelloWorld") {
println("HelloWorld")
}
-
按一下步骤找到任务 HelloWorld 双击运行。如果没有HelloWorld,就点下同步,编译一下。
- 控制台会出现一面的打印,我们看到执行结果跟普通代码里没有什么两样,正常打印。
4 把大象放冰箱里
task("openDoor") {
println("openDoor ")
}
task("putElephant") {
println("putElephant ")
}
task("closeDoor") {
println("closeDoor ")
}
运行结果:
dependsOn (任务的依赖):执行当前任务前 要先执行,dependsOn里面的内容 ,所以就可以顺序执行了
task("openDoor") {
println("openDoor ")
}
task("putElephant") {
println("putElephant ")
}.dependsOn("openDoor")//
task("closeDoor") {
println("closeDoor ")
}.dependsOn("putElephant")
但是如果我们把代码顺序换一下
task("closeDoor") {
println("closeDoor ")
}.dependsOn("putElephant")
task("putElephant") {
println("putElephant ")
}.dependsOn("openDoor")
task("openDoor") {
println("openDoor ")
}
运行结果: 打印结果的顺序与代码书写的先后一致。 那么,为什么dependsOn 没有起作用呢。
Tesk的生命周期(扫描和执行)
gradle 对脚本文件进行构建的时候,首先会扫描下,会对任务里闭包(花括号,蓝不打表达式)里声明的逻辑执行一下。所以上面代码是段声明式代码。 其实上面代码执行的顺序是 编译器扫面的顺序,如果我们想只有在执行时才打印呢?
doFirst / doLast 任务执行时才运行闭包里声明的代码
task("closeDoor") {
doLast() {
println("over ")
}
doFirst {
println("closeDoor ")
}
}.dependsOn("putElephant")
task("putElephant") {
doFirst {
println("putElephant ")
}
}.dependsOn("openDoor")
task("openDoor") {
doFirst {
println("openDoor ")
}
}
运行结果: 一个任务 一个逻辑,可以对比上面运行结果对比。
3. Gradle 任务集 Tasks
多任务的集合就是任务集
tasks() {
task("closeDoor") {
doLast {
println("over ")
}
doFirst {
println("closeDoor ")
}
}.dependsOn("putElephant")
task("putElephant") {
doFirst {
println("putElephant ")
}
}.dependsOn("openDoor")
task("openDoor") {
doFirst {
println("openDoor ")
}
}
}
4. Gradle 默认任务
1.properties 默认属性
task("plProperties") {
project.properties.forEach {
println("key: ${it.key} -- value: ${it.value}")
}
}
运行结果:
> Configure project :
key: parent -- value: null
key: classLoaderScope -- value: org.gradle.api.internal.initialization.DefaultClassLoaderScope@285a2c48
key: buildDir -- value: D:\IdeaProjects\untitled\build
key: configurations -- value: configuration container
key: plugins -- value: [org.gradle.api.plugins.HelpTasksPlugin@50aaf35f, org.gradle.buildinit.plugins.BuildInitPlugin@15b795bf, org.gradle.buildinit.plugins.WrapperPlugin@7e56c267, org.gradle.kotlin.dsl.provider.plugins.KotlinScriptRootPlugin@51df3340, org.gradle.kotlin.dsl.provider.plugins.KotlinScriptBasePlugin@56e8022f]
key: scriptHandlerFactory -- value: org.gradle.api.internal.initialization.DefaultScriptHandlerFactory@7fdb7f20
key: gradleKotlinDsl.projectAccessorsClassPath -- value: AccessorsClassPath(bin=[C:\Users\android\.gradle\caches\5.6.4\gradle-kotlin-dsl-accessors\592kebbqpm8qse0akhhq6udie\cache\classes], src=[C:\Users\android\.gradle\caches\5.6.4\gradle-kotlin-dsl-accessors\592kebbqpm8qse0akhhq6udie\cache\src])
key: objects -- value: org.gradle.api.internal.model.DefaultObjectFactory@37d6cf46
key: logger -- value: org.gradle.internal.logging.slf4j.OutputEventListenerBackedLogger@680906b3
key: deferredProjectConfiguration -- value: org.gradle.api.internal.project.DeferredProjectConfiguration@1f3bbfcf
key: rootDir -- value: D:\IdeaProjects\untitled
key: project -- value: root project 'untitled'
key: projectRegistry -- value: org.gradle.api.internal.project.DefaultProjectRegistry@9d42f7d
key: path -- value: :
key: normalization -- value: org.gradle.normalization.internal.DefaultInputNormalizationHandler_Decorated@2d526318
key: repositories -- value: repository container
key: childProjects -- value: {}
key: scriptPluginFactory -- value: org.gradle.configuration.ScriptPluginFactorySelector@2c7f350b
key: state -- value: project state 'EXECUTING'
key: resourceLoader -- value: org.gradle.internal.resource.transfer.DefaultUriTextResourceLoader@6ef8228c
key: plProperties -- value: task ':plProperties'
key: serviceRegistryFactory -- value: org.gradle.internal.service.scopes.ProjectScopeServices$4@467f57e9
key: tasks -- value: task set
key: group -- value:
key: artifacts -- value: org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated@788ba69d
key: ext -- value: org.gradle.internal.extensibility.DefaultExtraPropertiesExtension@2d0913ea
key: projectDir -- value: D:\IdeaProjects\untitled
key: dependencyLocking -- value: org.gradle.internal.locking.DefaultDependencyLockingHandler_Decorated@2cab885
key: configurationTargetIdentifier -- value: org.gradle.configuration.ConfigurationTargetIdentifier$1@3e36672a
key: projectEvaluationBroadcaster -- value: ProjectEvaluationListener broadcast
key: projectPath -- value: :
key: module -- value: org.gradle.api.internal.artifacts.ProjectBackedModule@1027e025
key: inheritedScope -- value: org.gradle.internal.extensibility.ExtensibleDynamicObject$InheritedDynamicObject@1bac913f
key: version -- value: unspecified
key: script -- value: false
key: dependencies -- value: org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler_Decorated@7e5f47e3
key: fileResolver -- value: org.gradle.api.internal.file.BaseDirFileResolver@2906d63d
key: extensions -- value: org.gradle.api.internal.plugins.DefaultConvention@2484eb00
key: kotlin.code.style -- value: official
key: modelRegistry -- value: org.gradle.model.internal.registry.DefaultModelRegistry@5bdeb3c6
key: projectEvaluator -- value: org.gradle.configuration.project.LifecycleProjectEvaluator@5f3a9701
key: projectConfigurator -- value: org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator@409215e5
key: name -- value: untitled
key: logging -- value: org.gradle.internal.logging.services.DefaultLoggingManager@43cd2a1c
key: configurationActions -- value: org.gradle.configuration.project.DefaultProjectConfigurationActionContainer@6da3f120
key: buildscript -- value: org.gradle.api.internal.initialization.DefaultScriptHandler@66aaf10a
key: status -- value: release
key: processOperations -- value: org.gradle.process.internal.DefaultExecActionFactory$DecoratingExecActionFactory@3647fd07
key: subprojects -- value: []
key: components -- value: SoftwareComponentInternal set
key: asDynamicObject -- value: DynamicObject for root project 'untitled'
key: displayName -- value: root project 'untitled'
key: identityPath -- value: :
key: parentIdentifier -- value: null
key: description -- value: null
key: antBuilderFactory -- value: org.gradle.api.internal.project.DefaultAntBuilderFactory@1c70bc19
key: buildPath -- value: :
key: fileOperations -- value: org.gradle.api.internal.file.DefaultFileOperations@6ea86446
key: pluginManager -- value: org.gradle.api.internal.plugins.DefaultPluginManager_Decorated@5fbbfa38
key: standardOutputCapture -- value: org.gradle.internal.logging.services.DefaultLoggingManager@43cd2a1c
key: defaultTasks -- value: []
key: modelSchemaStore -- value: org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore@6c61715
key: class -- value: class org.gradle.api.internal.project.DefaultProject_Decorated
key: buildScriptSource -- value: org.gradle.groovy.scripts.TextResourceScriptSource@569d8b0d
key: convention -- value: org.gradle.api.internal.plugins.DefaultConvention@2484eb00
key: allprojects -- value: [root project 'untitled']
key: baseClassLoaderScope -- value: org.gradle.api.internal.initialization.DefaultClassLoaderScope@4f9465b3
key: ant -- value: org.gradle.api.internal.project.DefaultAntBuilder@62b3a253
key: resources -- value: org.gradle.api.internal.resources.DefaultResourceHandler@62d9fe07
key: services -- value: ProjectScopeServices
key: gradle -- value: build 'untitled'
key: layout -- value: org.gradle.api.internal.file.DefaultProjectLayout@58a6d4b2
key: buildFile -- value: D:\IdeaProjects\untitled\build.gradle.kts
key: depth -- value: 0
key: mutationState -- value: project :
key: listenerBuildOperationDecorator -- value: org.gradle.configuration.internal.DefaultListenerBuildOperationDecorator@34738be8
key: rootProject -- value: root project 'untitled'
key: properties -- value: {parent=null, classLoaderScope=org.gradle.api.internal.initialization.DefaultClassLoaderScope@285a2c48, buildDir=D:\IdeaProjects\untitled\build, configurations=configuration container, plugins=[org.gradle.api.plugins.HelpTasksPlugin@50aaf35f, org.gradle.buildinit.plugins.BuildInitPlugin@15b795bf, org.gradle.buildinit.plugins.WrapperPlugin@7e56c267, org.gradle.kotlin.dsl.provider.plugins.KotlinScriptRootPlugin@51df3340, org.gradle.kotlin.dsl.provider.plugins.KotlinScriptBasePlugin@56e8022f], scriptHandlerFactory=org.gradle.api.internal.initialization.DefaultScriptHandlerFactory@7fdb7f20, gradleKotlinDsl.projectAccessorsClassPath=AccessorsClassPath(bin=[C:\Users\android\.gradle\caches\5.6.4\gradle-kotlin-dsl-accessors\592kebbqpm8qse0akhhq6udie\cache\classes], src=[C:\Users\android\.gradle\caches\5.6.4\gradle-kotlin-dsl-accessors\592kebbqpm8qse0akhhq6udie\cache\src]), objects=org.gradle.api.internal.model.DefaultObjectFactory@37d6cf46, logger=org.gradle.internal.logging.slf4j.OutputEventListenerBackedLogger@680906b3, deferredProjectConfiguration=org.gradle.api.internal.project.DeferredProjectConfiguration@1f3bbfcf, rootDir=D:\IdeaProjects\untitled, project=root project 'untitled', projectRegistry=org.gradle.api.internal.project.DefaultProjectRegistry@9d42f7d, path=:, normalization=org.gradle.normalization.internal.DefaultInputNormalizationHandler_Decorated@2d526318, repositories=repository container, childProjects={}, scriptPluginFactory=org.gradle.configuration.ScriptPluginFactorySelector@2c7f350b, state=project state 'EXECUTING', resourceLoader=org.gradle.internal.resource.transfer.DefaultUriTextResourceLoader@6ef8228c, plProperties=task ':plProperties', serviceRegistryFactory=org.gradle.internal.service.scopes.ProjectScopeServices$4@467f57e9, tasks=task set, group=, artifacts=org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated@788ba69d, ext=org.gradle.internal.extensibility.DefaultExtraPropertiesExtension@2d0913ea, projectDir=D:\IdeaProjects\untitled, dependencyLocking=org.gradle.internal.locking.DefaultDependencyLockingHandler_Decorated@2cab885, configurationTargetIdentifier=org.gradle.configuration.ConfigurationTargetIdentifier$1@3e36672a, projectEvaluationBroadcaster=ProjectEvaluationListener broadcast, projectPath=:, module=org.gradle.api.internal.artifacts.ProjectBackedModule@1027e025, inheritedScope=org.gradle.internal.extensibility.ExtensibleDynamicObject$InheritedDynamicObject@1bac913f, version=unspecified, script=false, dependencies=org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler_Decorated@7e5f47e3, fileResolver=org.gradle.api.internal.file.BaseDirFileResolver@2906d63d, extensions=org.gradle.api.internal.plugins.DefaultConvention@2484eb00, kotlin.code.style=official, modelRegistry=org.gradle.model.internal.registry.DefaultModelRegistry@5bdeb3c6, projectEvaluator=org.gradle.configuration.project.LifecycleProjectEvaluator@5f3a9701, projectConfigurator=org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator@409215e5, name=untitled, logging=org.gradle.internal.logging.services.DefaultLoggingManager@43cd2a1c, configurationActions=org.gradle.configuration.project.DefaultProjectConfigurationActionContainer@6da3f120, buildscript=org.gradle.api.internal.initialization.DefaultScriptHandler@66aaf10a, status=release, processOperations=org.gradle.process.internal.DefaultExecActionFactory$DecoratingExecActionFactory@3647fd07, subprojects=[], components=SoftwareComponentInternal set, asDynamicObject=DynamicObject for root project 'untitled', displayName=root project 'untitled', identityPath=:, parentIdentifier=null, description=null, antBuilderFactory=org.gradle.api.internal.project.DefaultAntBuilderFactory@1c70bc19, buildPath=:, fileOperations=org.gradle.api.internal.file.DefaultFileOperations@6ea86446, pluginManager=org.gradle.api.internal.plugins.DefaultPluginManager_Decorated@5fbbfa38, standardOutputCapture=org.gradle.internal.logging.services.DefaultLoggingManager@43cd2a1c, defaultTasks=[], modelSchemaStore=org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore@6c61715, class=class org.gradle.api.internal.project.DefaultProject_Decorated, buildScriptSource=org.gradle.groovy.scripts.TextResourceScriptSource@569d8b0d, convention=org.gradle.api.internal.plugins.DefaultConvention@2484eb00, allprojects=[root project 'untitled'], baseClassLoaderScope=org.gradle.api.internal.initialization.DefaultClassLoaderScope@4f9465b3, ant=org.gradle.api.internal.project.DefaultAntBuilder@62b3a253, resources=org.gradle.api.internal.resources.DefaultResourceHandler@62d9fe07, services=ProjectScopeServices, gradle=build 'untitled', layout=org.gradle.api.internal.file.DefaultProjectLayout@58a6d4b2, buildFile=D:\IdeaProjects\untitled\build.gradle.kts, depth=0, mutationState=project :, listenerBuildOperationDecorator=org.gradle.configuration.internal.DefaultListenerBuildOperationDecorator@34738be8, rootProject=root project 'untitled', properties=(this Map), providers=org.gradle.api.internal.provider.DefaultProviderFactory@751937c9}
key: providers -- value: org.gradle.api.internal.provider.DefaultProviderFactory@751937c9
> Task :plProperties UP-TO-DATE
BUILD SUCCESSFUL in 55ms
2. defaultTasks
把任务添加到默认任务里时,通过命令行执行时 直接写 gradle 就可以了,前提时你的电脑配置了gradle的环境变量.
task("plProperties") {
project.properties.forEach {
println("key: ${it.key} -- ${it.value}")
}
}
defaultTasks("plProperties")
5. Gradle 增量式更新 (UP-TO-DATE)
gradle 执行效率为什么时Maven的100倍. 就是因为 增量更新. 简单一句话就是在编译的时候,观察哪个文件变化了才去编译哪个文件,如果没有变化,就不再编译. 牺牲空间,节省时间
模仿打包时,gradle扫描源代码
基础代码: 会在项目根目录下生成一个 info.txt 文件, 内容都是src下的文件的全路径
plugins {
java
}
task("getSrcName") {
doFirst {
var infoTxt = file("info.txt")
var srcDir = fileTree("src")
srcDir.forEach {
if (it.isFile) {
Thread.sleep(1000)
infoTxt.appendText(it.absolutePath)
infoTxt.appendText(" \r\n ")
}
}
}
}
运行时间: 5s
不断双击任务: 会不断追写文件
用到的指令: inputs.dir() / inputs.file() / outputs.dir() / outputs.file
修改后
plugins {
java
}
task("getSrcName") {
// 如果被观察的输入输出都没有变化 这个任务就不会再执行了
inputs.dir("src") // 构建任务的输入
outputs.files("info.txt")// 构建任务的输出
doFirst {
var infoTxt = file("info.txt")
var srcDir = fileTree("src")
srcDir.forEach {
if (it.isFile) {
Thread.sleep(1000)
infoTxt.appendText(it.absolutePath)
infoTxt.appendText(" \r\n ")
}
}
}
}
第一次运行时间: 5s
第二次运行时间: 56ms (1 actionable task: 1
up-to-date
) 新的重复的没有变化的文件,不再执行
修改src下的某一个代码文件
第三次运行时间: 5秒
6. Gradle 常用插件
application插件
plugins {
application
}
application {
mainClassName = "Test"
}
public class Test {
public static void main(String[] args) {
System.out.println("Hello");
}
}
war插件
java插件
kotlin插件