如何从Gradle的`pluginManagement {}`块调用函数?

9rnv2umw  于 2023-04-06  发布在  其他
关注(0)|答案(3)|浏览(221)

简介

您好,我正在尝试删除应用程序settings.gradle中的重复代码。以下是我的文件当前的样子:

pluginManagement {
    def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
    def properties = new Properties()
    assert localPropertiesFile.exists()
    localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
    def flutterSdkPath = properties.getProperty("flutter.sdk")
    assert flutterSdkPath != null, "flutter.sdk not set in local.properties"

    includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

    plugins {
        id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
    }
}

include ':app'

def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

(You我可以忽略特定于技术的事情以及为什么必须这样做-让我们假设 * 必须这样做 *。如果您对更多细节感兴趣,请参阅this PR to Flutter
很容易看出,负责从local.properties文件中加载flutter.sdk属性的代码重复了两次,因此我着手删除这种重复。

尝试1(变量)

起初,我尝试了下面的代码,但Gradle很快提醒我“pluginManagement {}块必须出现在脚本中的任何其他语句之前”。

def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"

pluginManagement {
    includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

    plugins {
        id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
    }
}

include ':app'

apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

尝试2(函数)

在前面的尝试中,错误消息说在pluginManagement {}块之前不允许有 * 语句 *。我考虑过将代码移到一个单独的函数中,因为,在我(适度)的理解中,函数不是Groovy中的语句:

String flutterSdkPath() {
    def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
    def properties = new Properties()
    assert localPropertiesFile.exists()
    localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
    def flutterSdkPath = properties.getProperty("flutter.sdk")
    assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
    return flutterSdkPath
}

pluginManagement {
    includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

    plugins {
        id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
    }
}

include ':app'

apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

不幸的是,它仍然不起作用,并且错误只会变得不那么有用:

FAILURE: Build failed with an exception.

* Where:
Settings file '/Users/bartek/fvm/versions/master/examples/hello_world/android/settings.gradle' line: 20

* What went wrong:
A problem occurred evaluating settings 'android'.
> Could not get unknown property 'flutterSdkPath' for object of type org.gradle.plugin.management.internal.DefaultPluginManagementSpec.

我很确定它必须做一些关于如何pluginManagement {}块被Gradle以特殊的方式处理的事情(也就是说,在settings.gradle中的其余代码被评估之前,它首先被评估)

尝试3(类中的静态方法)

我想也许所有在pluginManagement {}块之前的代码都被剥离了(?),所以我尝试创建一个包含静态方法的类:

pluginManagement {
    includeBuild("${Flutter.flutterSdkPath}/packages/flutter_tools/gradle")

    plugins {
        id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
    }
}

include ':app'

apply from: "${Flutter.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle"

class Flutter {
    String flutterSdkPath() {
        def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
        def properties = new Properties()
        assert localPropertiesFile.exists()
        localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
        def flutterSdkPath = properties.getProperty("flutter.sdk")
        assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
        return flutterSdkPath
    }
}

这一次,错误消息甚至更没有帮助:

* Where:
Settings file '/Users/bartek/fvm/versions/master/examples/hello_world/android/settings.gradle' line: 11

* What went wrong:
A problem occurred evaluating settings 'android'.
> Flutter

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

在使用--stracktrace标志运行Gradle后,我注意到这行:

... (<very long stack trace>)
Caused by: java.lang.NoClassDefFoundError: Flutter
...

这和我在第二次尝试中遇到的问题是一样的。
我不知道如何将属性加载代码移到一个地方,并从pluginManagement {}块的内部和外部调用它。
我认为Gradle设置插件可以在这里工作,但我宁愿不这样做,除非必要。

gcuhipw9

gcuhipw91#

pluginManagement块中应只包含插件相关配置:声明插件版本、应用插件和配置插件仓库。它应该是第一个块的原因是它在项目中的其他gradle文件之前运行。该块的目的不是用于通用脚本或导入其他文件。

不需要过度工程化。您想要提取的功能只是从properties文件中获取变量。

使用gradle.properties

settings.gradle文件所在的项目根目录下创建一个文件gradle.properties,并添加:

flutterSdkPath=PATH_TO_YOUR_FLUTTER_SDK

settings.gradle中,您可以使用它:

pluginManagement {
    includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

    plugins {
        id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
    }
}

include ':app'

apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

有关如何使用Kotlin的参考和更多信息,请阅读插件版本管理

使用命令行注入

有多种方法可以实现。在这里你可以阅读更多关于Gradle, System, Environment, and Project properties的内容。它们从高优先级到低优先级的层次结构以及它们如何覆盖这些值:
1.命令行属性
1.系统特性
1.环境变量
1.主目录中的gradle.properties
1.项目根目录中的gradle.properties
简而言之,您只需要通过命令行将变量传递给gradle命令
举一个简短的例子:

gradle -PflutterSdkPath=$(cat local.properties | grep flutterSdkPath | cut -d'=' -f2) <GRADLE_TASK>
blpfk2vs

blpfk2vs2#

不幸的是,它仍然不起作用,并且错误只会变得不那么有用:
它说你试图引用的属性没有找到,因为你把它变成了一个方法,所以不再有这样的属性了。
如果您尝试调用该方法,它会告诉您未找到该方法。
我很确定它必须做一些关于如何pluginManagement {}块被Gradle以特殊的方式处理的事情(也就是说,在settings.gradle中的其余代码被评估之前,它首先被评估)
确切地说,它是单独提取和评估的。pluginManagement块可以定义插件存储库或包含带有设置插件的构建,因此要编译脚本的其余部分,它需要首先单独评估。这也是你不能使用块外部的属性或方法的原因。它必须是自包含的。
我想也许所有在pluginManagement {}块之前的代码都被剥离了(?),所以我尝试创建一个包含静态方法的类:
就像我说的,所有的都被“剥离”了,否则你也可以简单地在块后面定义方法并调用它。
我认为Gradle设置插件可以在这里工作,但我宁愿不这样做,除非必要。
设置插件在pluginManagement块之后被评估,因为该块可以定义包含的构建,其中包含设置插件或存储库,可以在其中找到设置插件,所以设置插件太晚了,无法配置该块。
PS我也很乐意接受一个解释,为什么我在尝试1)的早期得到了一个错误,而不是在尝试2)。
不知道你说的“早期”是什么意思,这两个错误都或多或少是立即出现的。(它在KotlinDSL中是允许的,但在块内使用也不起作用),因此在解析脚本以提取块时会出错,而在尝试2中,当实际评估块时,由于它使用不存在的属性,因此会出现错误。
你可以通过使用“额外”属性来实现你想要实现的目标。使用它们通常是一种代码气味,只是一种解决方法,用于不正确地做一些事情,但这可能是使用它可能合适的罕见情况之一。
虽然pluginManagment块是单独计算的,但它仍然可以修改模型,因此您可以添加一个闭包作为额外的属性,然后该属性也可用于剩余的脚本:

pluginManagement {
    settings.ext.foo = { "Foo" }
    println("1: ${foo()}")
    includeBuild("${foo()}")
}

println("2: ${foo()}")
eivgtgni

eivgtgni3#

在gradle.properties项目的根目录下创建一个文件www.example.com

pluginManagement {
    includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

    plugins {
        id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
    }
}

相关问题