Hi all, this is my first post on Gradle forums. I have a problem with Gradle and would be very grateful for any help. I originally posted this on StackOverflow, but didn’t receive satisfying responses, so I thought that the official forum might be a good place to ask:)
Introduction
I’m trying to deduplicate the code found in my app’s settings.gradle
. Here’s what my file looks like currently:
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 can ignore the technology-specific things and why it has to be done like this – let’s just assume it has to be done like this. If you’re interested in more details, please see this PR to Flutter)
It’s easy to see that the code responsible for loading flutter.sdk
property from the local.properties
file is duplicated twice. So I set out to remove this duplication.
Attempt 1 (variable)
At first, I tried the below code, only to be quickly reminded by Gradle that the “the pluginManagement {} block must appear before any other statements in the script.”
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"
Attempt 2 (function)
The error message in the previous attempt says that no statements are allowed before the pluginManagement {}
block. I thought about moving the code to a separate function, since, in my (modest) understanding, function isn’t a statement in 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"
Unfortunately, it still doesn’t work, and the error only got less helpful:
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.
I’m pretty sure it has to do something with how to pluginManagement {}
block is treated by Gradle in a special way (that is, it’s evaluated first, before the rest of code in settings.gradle
is evaluated)
Attempt 3 (static method in a class)
I thought that maybe all code that’s before the pluginManagement {}
block is somehow stripped (?), so I tried creating a class with a static method in it:
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
}
}
This time the error message was even less helpful:
* 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.
After running Gradle with the --stracktrace
flag, I noticed this line:
... (<very long stack trace>)
Caused by: java.lang.NoClassDefFoundError: Flutter
...
Looks like the same problem that I encountered in attempt 2).
I have no more ideas on how to move the properties-loading code to a single place and call it from the inside of the pluginManagement {}
block and from its outside. So, I’m turning to you
I think a Gradle Settings Plugin could work here, but I’d prefer not to do it unless necessary.
PS I’d also happily accept an explanation as to why I got an error early in attempt 1), but not in attempt (2).