如何在 build.gradle 中定义和调用自定义方法?

作为项目的一部分,我需要从一个目录中读取文件,并在构建脚本中执行所有这些操作。对于每个文件,操作都是相同的(读取一些 SQL 查询并执行它)。我认为这是一个重复的任务,最好写在一个方法里面。因为我是新来的,我不知道应该怎么做。请帮帮我。

100086 次浏览

One approach given below:

ext.myMethod = { param1, param2 ->
// Method body here
}

Note that this gets created for the project scope, ie. globally available for the project, which can be invoked as follows anywhere in the build script using myMethod(p1, p2) which is equivalent to project.myMethod(p1, p2)

The method can be defined under different scopes as well, such as within tasks:

task myTask {
ext.myMethod = { param1, param2 ->
// Method body here
}


doLast {
myMethod(p1, p2) // This will resolve 'myMethod' defined in task
}
}

You can define methods in the following way:

// Define an extra property
ext.srcDirName = 'src/java'


// Define a method
def getSrcDir(project) {
return project.file(srcDirName)
}

You can find more details in gradle documentation Chapter 62. Organizing Build Logic

If you have defined any methods in any other file *.gradle - ext.method() makes it accessible project wide. For example here is a

versioning.gradle

// ext makes method callable project wide
ext.getVersionName = { ->
try {
def branchout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
standardOutput = branchout
}
def branch = branchout.toString().trim()


if (branch.equals("master")) {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'describe', '--tags'
standardOutput = stdout
}
return stdout.toString().trim()
} else {
return branch;
}
}
catch (ignored) {
return null;
}
}

build.gradle

task showVersion << {
// Use inherited method
println 'VersionName: ' + getVersionName()
}

Without ext.method() format , the method will only be available within the *.gradle file it is declared. This is the same with properties.

An example with a root object containing methods.

hg.gradle file:

ext.hg = [


cloneOrPull: { source, dest, branch ->
if (!dest.isDirectory())
hg.clone(source, dest, branch)
else
hg.pull(dest)
hg.update(dest, branch)
},


clone: { source, dest, branch ->
dest.mkdirs()
exec {
commandLine 'hg', 'clone', '--noupdate', source, dest.absolutePath
}
},


pull: { dest ->
exec {
workingDir dest.absolutePath
commandLine 'hg', 'pull'
}
},


]

build.gradle file

apply from: 'hg.gradle'


hg.clone('path/to/repo')

Somehow, maybe because it's five years since the OP, but none of the

ext.someMethod = { foo ->
methodBody
}

approaches are working for me. Instead, a simple function definition seems to be getting the job done in my gradle file:

def retrieveEnvvar(String envvar_name) {
if ( System.getenv(envvar_name) == "" ) {
throw new InvalidUserDataException("\n\n\nPlease specify environment variable ${envvar_name}\n")
} else {
return System.getenv(envvar_name)
}
}

And I call it elsewhere in my script with no prefix, ie retrieveEnvvar("APP_PASSWORD")

This is 2020 so I'm using Gradle 6.1.1.

@ether_joe the top-voted answer by @InvisibleArrow above does work however you must define the method you call before you call it - i.e. earlier in the build.gradle file.

You can see an example here. I have used this approach with Gradle 6.5 and it works.

With Kotlin DSL (build.gradle.kts) you can define regular functions and use them.
It doesn't matter whether you define your function before the call site or after it.

println(generateString())


fun generateString(): String {
return "Black Forest"
}


tasks.create("MyTask") {
println(generateString())
}

If you want to import and use a function from another script, see this answer and this answer.