Flutter Gradle KTS: “Unresolved reference: flutterRoot” в settings.gradle.kts при добавлении локального репозитория maven для pluginManagement
Я столкнулся с проблемой конфигурации Gradle в моем Flutter-проекте при попытке настройки Deferred Components. После решения ошибки “v1 embedding” путем пересоздания проекта, теперь я столкнулся с ошибкой компиляции в файле settings.gradle.kts.
Описание проблемы
Ошибка возникает при попытке добавления локального репозитория плагинов Flutter внутри блока pluginManagement:
Unresolved reference: flutterRoot
Текущая конфигурация
Вот мой полный файл settings.gradle.kts:
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()
// Ошибка происходит на следующей строке
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")
Вопрос
Как правильно определить переменную flutterRoot, чтобы она была доступна внутри блока pluginManagement в Gradle Kotlin DSL? Я явно упускаю что-то фундаментальное относительно области видимости переменных в этом контексте.
Любые рекомендации по решению ошибки “Unresolved reference: flutterRoot” будут очень признательны.
Ошибка “Unresolved reference: flutterRoot”
Ошибка “Unresolved reference: flutterRoot” возникает из-за того, что переменные, определенные на верхнем уровне settings.gradle.kts, недоступны внутри блока pluginManagement из-за правил области видимости Gradle. Решением является либо перемещение определения переменной внутрь блока pluginManagement, либо использование системы свойств Gradle для обеспечения ее доступности во всем файле.
Содержание
- Понимание проблемы области видимости
- Решение 1: Перемещение переменных внутрь pluginManagement
- Решение 2: Использование свойств Gradle
- Решение 3: Использование провайдеров
- Полная рабочая конфигурация
- Лучшие практики настройки Flutter Gradle
- Устранение дополнительных проблем
Понимание проблемы области видимости
В Gradle Kotlin DSL блок pluginManagement имеет собственный контекст оценки и область видимости. Переменные, определенные на верхнем уровне settings.gradle.kts, автоматически недоступны внутри этого блока, что является причиной возникновения ошибки “Unresolved reference: flutterRoot”.
Как объясняется в обсуждениях на форумах Gradle, это распространенная проблема при миграции между версиями Gradle, особенно с версии 5.x на 6.x и более поздние, где правила области видимости стали более строгими.
Проблема возникает потому, что Gradle оценивает блок pluginManagement на ранней фазе конфигурации, до того как получает доступ к переменным, определенным в основной области видимости скрипта.
Решение 1: Перемещение переменных внутрь pluginManagement
Наиболее прямое решение - переместить определения переменных непосредственно внутрь блока pluginManagement, где они нужны:
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
// Загружаем локальные свойства и flutter root внутри блока
val localProps = Properties()
File(rootDir, "local.properties").takeIf { it.isFile }?.inputStream()?.use {
localProps.load(it)
}
val flutterRoot = localProps.getProperty("flutter.sdk")
?: error("flutter.sdk не установлен в local.properties")
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")
Этот подход работает, потому что переменные теперь определены в той же области видимости, где они используются.
Решение 2: Использование свойств Gradle
Для лучшей организации и повторного использования можно использовать систему свойств Gradle для обеспечения доступности переменных во всем файле настроек:
// Определяем свойства на верхнем уровне
val flutterRoot: String by settings
val localProperties: Properties by settings
// Инициализируем свойства
settingsEvaluated {
val props = Properties()
File(rootDir, "local.properties").takeIf { it.isFile }?.inputStream()?.use {
props.load(it)
}
localProperties["flutter.sdk"] = props.getProperty("flutter.sdk")
?: error("flutter.sdk не установлен в local.properties")
flutterRoot = localProperties["flutter.sdk"] as String
}
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
// Теперь flutterRoot доступен
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")
Этот подход обеспечивает лучшую организацию и делает переменные доступными во всем файле настроек.
Решение 3: Использование провайдеров
Для более современного подхода, совместимого с последними версиями Gradle, можно использовать провайдеры:
import org.gradle.api.provider.Provider
val flutterRootProvider: Provider<String> = providers.gradleProperty("flutter.sdk")
.orElse(providers.provider {
error("flutter.sdk не установлен в local.properties")
})
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
// Используем провайдер
maven(url = File(flutterRootProvider.get(), "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")
Этот подход более надежен и обрабатывает разрешение свойств отложенным образом.
Полная рабочая конфигурация
Вот полная рабочая конфигурация, решающая проблему области видимости:
import java.util.Properties
import java.io.File
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
// Безопасная загрузка свойств внутри pluginManagement
val flutterSdkPath = {
val properties = Properties()
val localPropsFile = File(rootDir, "local.properties")
if (localPropsFile.isFile) {
localPropsFile.inputStream().use { properties.load(it) }
}
properties.getProperty("flutter.sdk") ?: error("flutter.sdk не установлен в local.properties")
}()
maven(url = File(flutterSdkPath, "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")
Эта конфигурация:
- Определяет путь к SDK Flutter непосредственно внутри блока
pluginManagement - Использует безопасный подход к загрузке свойств с обработкой ошибок
- Сохраняет всю необходимую функциональность для Deferred Components
Лучшие практики настройки Flutter Gradle
На основе результатов исследования, вот некоторые лучшие практики:
-
Используйте синтаксис Plugin DSL: Как указано в документации Flutter, перейдите от императивного синтаксиса
apply plugin:к современному синтаксисуplugins { id ... }. -
Обеспечьте совместимость версии Gradle: Ошибки “Unresolved reference” часто вызваны использованием устаревшей версии Gradle. Убедитесь, что вы используете Gradle 6.8 или более позднюю версию для поддержки
dependencyResolutionManagement. -
Организуйте ваш settings.gradle.kts: Держите связанные конфигурации вместе и используйте соответствующую область видимости, чтобы избежать ошибок ссылок.
-
Безопасно обрабатывайте локальные свойства: Всегда проверяйте, существует ли файл local.properties, прежде чем пытаться его прочитать.
-
Используйте правильную обработку ошибок: Предоставляйте осмысленные сообщения об ошибках, когда требуемые свойства отсутствуют.
Устранение дополнительных проблем
Если вы столкнетесь с аналогичными проблемами, рассмотрите следующие дополнительные шаги по устранению неполадок:
-
Проверьте версию Gradle wrapper: Убедитесь, что ваш
gradle-wrapper.propertiesиспользует совместимую версию. -
Обновите Android Gradle Plugin: Убедитесь, что вы используете совместимую версию Android Gradle Plugin.
-
Очистите и пересоберите: Иногда простая очистка проекта и пересборка может решить проблемы конфигурации.
-
Проверьте наличие устаревшего синтаксиса: Удалите все устаревшие операторы
apply plugin:и используйте современный plugin DSL. -
Проверьте версии плагинов: Убедитесь, что все версии плагинов совместимы друг с другом и с вашей версией Flutter.
Ключевой вывод заключается в том, что Gradle Kotlin DSL имеет определенные правила области видимости, и переменные должны быть определены в соответствующей области видимости, где они используются. Перемещая разрешение пути к SDK Flutter внутрь блока pluginManagement, вы можете устранить ошибку “Unresolved reference: flutterRoot” и успешно настроить свой Flutter проект с Deferred Components.
Источники
- Руководство по миграции Flutter Gradle Plugin
- Форумы Gradle - Неопределенные ссылки в settings.gradle.kts
- Stack Overflow - Неопределенная ссылка: dependencyResolutionManagement
- Проблема Gradle #34145 - Неопределенная ссылка pluginManagement
- Stack Overflow - Проблема свойств settings.gradle.kts Gradle 6
Заключение
- Ошибка “Unresolved reference: flutterRoot” возникает из-за правил области видимости Gradle в Kotlin DSL
- Перемещайте определения переменных внутрь блока
pluginManagement, где они нужны - Используйте свойства Gradle или провайдеры для лучшей организации и повторного использования
- Убедитесь, что ваша версия Gradle совместима (6.8+ для современных функций)
- Следуйте рекомендованному синтаксису plugin DSL Flutter вместо устаревшего императивного apply
- Всегда безопасно обрабатывайте локальные свойства с правильной проверкой ошибок
Реализуя эти решения, вы можете успешно настроить свой Flutter проект с Deferred Components и избежать проблем конфигурации Gradle.