How to resolve “Unresolved reference: flutterRoot” error in settings.gradle.kts when adding local maven repository for pluginManagement in Flutter?
I’m encountering a compilation error in my settings.gradle.kts file when trying to add a local Flutter plugin repository inside the pluginManagement block. The error message is “Unresolved reference: flutterRoot”, which suggests that the flutterRoot variable I’m defining at the top of the file isn’t in scope within the pluginManagement block.
Here’s my current settings.gradle.kts file:
import java.util.Properties
import java.io.File
fun loadLocalProperties(rootDir: File): Properties {
val props = Properties()
val localPropsFile = File(rootDir, "local.properties")
if (localPropsFile.isFile) {
localPropsFile.inputStream().use { props.load(it) }
}
return props
}
val localProperties = loadLocalProperties(rootProject.projectDir)
val flutterRoot = localProperties.getProperty("flutter.sdk")
?: error("flutter.sdk not set in local.properties")
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
// Error occurs on the next line
maven(url = File(flutterRoot, "packages/flutter_tools/gradle/flutter_plugin_loader_repo").toURI())
}
}
plugins {
id("com.android.settings") version "8.3.0"
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
}
include(":app", ":modelComponent")
project(":modelComponent").projectDir = file("modelComponent")
What’s the correct way to define flutterRoot so it’s accessible inside the pluginManagement block in Gradle Kotlin DSL?
The “Unresolved reference: flutterRoot” error occurs because variables defined at the top level of settings.gradle.kts aren’t accessible within the pluginManagement block due to scope limitations in Gradle Kotlin DSL. To resolve this, you need to move the variable definition inside the pluginManagement block where it’s needed.
Here’s the corrected version of your settings.gradle.kts:
import java.util.Properties
import java.io.File
pluginManagement {
// Define flutterRoot inside this block where it's needed
val flutterRoot = run {
val properties = java.util.Properties()
val localPropsFile = File(rootProject.projectDir, "local.properties")
if (localPropsFile.isFile) {
localPropsFile.inputStream().use { properties.load(it) }
}
val flutterSdkPath = properties.getProperty("flutter.sdk")
?: error("flutter.sdk not set in local.properties")
flutterSdkPath
}
repositories {
google()
mavenCentral()
gradlePluginPortal()
// Now flutterRoot is accessible here
maven(url = File(flutterRoot, "packages/flutter_tools/gradle/flutter_plugin_loader_repo").toURI())
}
}
plugins {
id("com.android.settings") version "8.3.0"
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
}
include(":app", ":modelComponent")
project(":modelComponent").projectDir = file("modelComponent")
Contents
- Understanding the Scope Issue
- Correct Variable Definition in pluginManagement
- Alternative Solutions
- Best Practices for Flutter Gradle Configuration
- Troubleshooting Common Issues
Understanding the Scope Issue
The core problem lies in how Gradle Kotlin DSL handles variable scope in settings files. As mentioned in the Gradle Kotlin DSL documentation, variables defined at the top level of settings.gradle.kts aren’t automatically accessible within nested blocks like pluginManagement.
This is a fundamental limitation of the Kotlin DSL in Gradle settings files. The Gradle Forums discussion confirms that “variables defined in the settings.gradle.kts cannot be referenced in the plugins block” - and the same limitation applies to pluginManagement.
Correct Variable Definition in pluginManagement
The solution is to define the flutterRoot variable directly within the pluginManagement block where it’s needed. This approach follows the standard pattern used in Flutter’s official documentation:
pluginManagement {
val flutterRoot = run {
val properties = java.util.Properties()
val localPropsFile = File(rootProject.projectDir, "local.properties")
if (localPropsFile.isFile) {
localPropsFile.inputStream().use { properties.load(it) }
}
val flutterSdkPath = properties.getProperty("flutter.sdk")
?: error("flutter.sdk not set in local.properties")
flutterSdkPath
}
repositories {
google()
mavenCentral()
gradlePluginPortal()
maven(url = File(flutterRoot, "packages/flutter_tools/gradle/flutter_plugin_loader_repo").toURI())
}
}
This approach ensures the variable is in the correct scope and accessible within the repositories block.
Alternative Solutions
1. Using settingsEvaluated Hook
For more complex scenarios, you can use the settingsEvaluated hook:
settingsEvaluated { settings ->
val flutterRoot = run {
val properties = java.util.Properties()
val localPropsFile = File(rootProject.projectDir, "local.properties")
if (localPropsFile.isFile) {
localPropsFile.inputStream().use { properties.load(it) }
}
val flutterSdkPath = properties.getProperty("flutter.sdk")
?: error("flutter.sdk not set in local.properties")
flutterSdkPath
}
settings.pluginManagement.repositories.apply {
maven(url = File(flutterRoot, "packages/flutter_tools/gradle/flutter_plugin_loader_repo").toURI())
}
}
2. Predefined Flutter SDK Path
If you need the flutterRoot variable in multiple places, define it once in pluginManagement and then reference it:
pluginManagement {
val flutterRoot = run {
val properties = java.util.Properties()
val localPropsFile = File(rootProject.projectDir, "local.properties")
if (localPropsFile.isFile) {
localPropsFile.inputStream().use { properties.load(it) }
}
val flutterSdkPath = properties.getProperty("flutter.sdk")
?: error("flutter.sdk not set in local.properties")
flutterSdkPath
}
repositories {
google()
mavenCentral()
gradlePluginPortal()
maven(url = File(flutterRoot, "packages/flutter_tools/gradle/flutter_plugin_loader_repo").toURI())
}
}
// Now you can use flutterRoot in other parts of your settings file
// It will be available in the settings script scope
Best Practices for Flutter Gradle Configuration
1. Follow Official Flutter Patterns
The Flutter documentation shows the recommended approach for handling Flutter SDK paths:
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
2. Error Handling
Always include proper error handling when reading properties:
val flutterRoot = run {
val properties = java.util.Properties()
val localPropsFile = File(rootProject.projectDir, "local.properties")
if (localPropsFile.isFile) {
localPropsFile.inputStream().use { properties.load(it) }
}
val flutterSdkPath = properties.getProperty("flutter.sdk")
?: error("flutter.sdk not set in local.properties")
flutterSdkPath
}
3. Repository Configuration Order
Configure repositories in the correct order - local repositories first, then remote ones:
repositories {
mavenLocal() // If you have local plugins
maven(url = File(flutterRoot, "packages/flutter_tools/gradle/flutter_plugin_loader_repo").toURI())
google()
mavenCentral()
gradlePluginPortal()
}
Troubleshooting Common Issues
1. File Not Found Errors
If you encounter file-related errors, ensure the local.properties file exists and has the correct path:
flutter config --android-sdk <your-sdk-path>
2. Repository Resolution Issues
If plugins can’t be resolved, check your repository configuration:
settingsEvaluated { settings ->
settings.pluginManagement.resolutionStrategy {
eachPlugin {
// Force specific versions if needed
when (requested.id.id) {
"com.android.application" -> useVersion("8.3.0")
}
}
}
}
3. Kotlin DSL Syntax Errors
Ensure you’re using the correct Kotlin DSL syntax:
// Correct
maven(url = File(flutterRoot, "path/to/repo").toURI())
// Incorrect
maven { url = "$flutterRoot/path/to/repo" }
The key takeaway is that in Gradle Kotlin DSL settings files, variables must be defined in the same scope where they’re used. For pluginManagement blocks, this means defining variables directly within that block rather than at the top level of the file.
Sources
- Gradle Kotlin DSL Primer - Official Documentation
- Flutter Android Gradle Plugin Documentation
- Gradle Forums: Kotlin DSL Variable Scope Discussion
- Stack Overflow: Unresolved Reference in Settings Gradle KTS
- Flutter Plugins Configuration Documentation
Conclusion
The “Unresolved reference: flutterRoot” error is a common issue when working with Gradle Kotlin DSL in Flutter projects. The solution involves understanding variable scope limitations and defining variables in the appropriate scope. By moving the flutterRoot variable definition inside the pluginManagement block, you ensure it’s accessible where needed. Always follow Flutter’s official patterns and include proper error handling for robust configuration. Remember that in settings.gradle.kts, variable scope is strictly limited to where they’re defined, so plan your configuration accordingly.