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

Posted

技术标签:

【中文标题】如何在 build.gradle 中定义和调用自定义方法【英文标题】:How to define and call custom methods in build.gradle 【发布时间】:2015-03-02 21:02:02 【问题描述】:

作为我项目的一部分,我需要从目录中读取文件并在构建脚本中执行所有这些操作。对于每个文件,操作都是相同的(读取一些 sql 查询并执行它)。我认为这是一项重复性的任务,最好在方法中编写。由于我是 gradle 新手,我不知道应该如何。请帮忙。

【问题讨论】:

gradle.org/docs/current/userguide/userguide_single.html#N1034A 【参考方案1】:

下面给出的一种方法:

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

请注意,这是为项目范围创建的,即。全局可用于项目,可以在构建脚本中的任何位置使用myMethod(p1, p2)调用如下,相当于project.myMethod(p1, p2)

该方法也可以在不同的范围内定义,例如在任务中:

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

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

【讨论】:

还有一个疑问。我可以标记任务本地的方法吗? ext.myMethod 会将其标记为全局。 当我们使用ext时,作用域被限制在定义的地方,即。如果它是在任务下定义的,则它是任务本地的。它的工作方式是通过实现ExtensionAware 的实体(如项目、任务等)。这将添加一个通过 ext 指令配置的 ExtraPropertiesExtension。 这意味着我可以在不同的任务中使用相同的方法名而不会发生任何冲突。 IE; ext.myMethod 在两个或更多任务中应该可以工作。 从子项目访问时,可以通过rootProject.ext.myMethod(p1, p2)访问【参考方案2】:

您可以通过以下方式定义方法:

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

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

您可以在 gradle 文档Chapter 62. Organizing Build Logic中找到更多详细信息

【讨论】:

我试过了,但是我正在创建的方法会在我正在运行的每个任务上执行,例如在尝试运行 ./gradlew clean 时 - 我看到该方法正在执行,这不是什么我想 - 你知道可能是什么问题吗? @user1002065 很难在没有看到您的设置的情况下判断,如果您可以分享(即作为要点),那么我可以尝试提供帮助【参考方案3】:

如果您在任何其他文件 *.gradle 中定义了任何方法 - ext.method() 使其可在项目范围内访问。例如这里是一个

版本控制.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()

如果没有 ext.method() 格式,该方法将仅在它声明的 *.gradle 文件中可用。属性也是如此。

【讨论】:

【参考方案4】:

一个包含方法的根对象的示例。

hg.gradle 文件:

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 文件

apply from: 'hg.gradle'

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

【讨论】:

【参考方案5】:

不知何故,也许是因为距 OP 已经五年了,但没有一个

ext.someMethod =  foo ->
   methodBody

方法对我有用。相反,一个简单的函数定义似乎可以在我的 gradle 文件中完成工作:

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)
           

我在脚本的其他地方不带前缀地称呼它,即retrieveEnvvar("APP_PASSWORD")

现在是 2020 年,所以我使用的是 Gradle 6.1.1。

【讨论】:

我也在 gradle 6.1.1,ex.someMethod = 工作正常。只是我在调用 lambda 时不能使用参数名称。 当然可以,但是您的方法只存在于该脚本中。因此,当您在两个地方需要相同的功能时,很遗憾,它并没有帮助。【参考方案6】:

@ether_joe 上面@InvisibleArrow 投票率最高的答案确实 有效,但是您必须定义您调用的方法before 您调用它 - 即在build.gradle 之前文件。

你可以看到一个例子here。我已经在 Gradle 6.5 中使用了这种方法,并且可以正常工作。

【讨论】:

以上是关于如何在 build.gradle 中定义和调用自定义方法的主要内容,如果未能解决你的问题,请参考以下文章

自定义通知Notification:自己定义通知Notification下拉后的显示样式

如何在 build.gradle 中为不同的 productFlavors 定义 android:label

如何在build.gradle中创建文件并设置环境变量并获取文件内的数据?

如何调试 Gradle build.gradle 文件(在调试器中,带有断点)?

Gradle中的build.gradle文件

Gradle:是不是可以在 gradle 插件中定义 CustomTask 并从 build.gradle 中扩展该类?