НейроАгент

Исправление ошибки FlutterRoot в settings.gradle.kts

Решение ошибки 'Unresolved reference: flutterRoot' в Gradle Kotlin DSL путем правильного определения переменных в области видимости блока pluginManagement.

Вопрос

Как исправить ошибку “Unresolved reference: flutterRoot” в файле settings.gradle.kts при добавлении локального репозитория maven для pluginManagement в Flutter?

Я столкнулся с ошибкой компиляции в файле settings.gradle.kts при попытке добавить локальный репозиторий плагина Flutter внутри блока pluginManagement. Сообщение об ошибке: “Unresolved reference: flutterRoot”, что указывает на то, что переменная flutterRoot, определенная вверху файла, не находится в области видимости внутри блока pluginManagement.

Вот мой текущий файл settings.gradle.kts:

kotlin
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” возникает из-за того, что переменные, определенные на верхнем уровне settings.gradle.kts, недоступны внутри блока pluginManagement из-за ограничений области видимости в Gradle Kotlin DSL. Для решения этой проблемы необходимо переместить определение переменной внутрь блока pluginManagement, где оно требуется.

Вот исправленная версия вашего settings.gradle.kts:

kotlin
import java.util.Properties
import java.io.File

pluginManagement {
    // Определяем flutterRoot внутри этого блока, где он нужен
    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()
        // Теперь 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")

Содержание


Понимание проблемы области видимости

Основная проблема заключается в том, как Gradle Kotlin DSL обрабатывает область видимости переменных в файлах настроек. Как упоминается в документации Gradle Kotlin DSL, переменные, определенные на верхнем уровне settings.gradle.kts, автоматически недоступны внутри вложенных блоков, таких как pluginManagement.

Это фундаментальное ограничение Kotlin DSL в файлах настроек Gradle. Обсуждение на форумах Gradle подтверждает, что “переменные, определенные в settings.gradle.kts, не могут быть использованы в блоке plugins” - и то же ограничение применимо к pluginManagement.

Правильное определение переменной в pluginManagement

Решение заключается в определении переменной flutterRoot непосредственно внутри блока pluginManagement, где она требуется. Этот подход соответствует стандартному шаблону, используемому в официальной документации Flutter:

kotlin
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())
    }
}

Этот подход гарантирует, что переменная находится в правильной области видимости и доступна внутри блока repositories.

Альтернативные решения

1. Использование хука settingsEvaluated

Для более сложных сценариев можно использовать хук settingsEvaluated:

kotlin
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. Предопределенный путь к Flutter SDK

Если вам нужна переменная flutterRoot в нескольких местах, определите ее один раз в pluginManagement, а затем ссылайтесь на нее:

kotlin
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())
    }
}

// Теперь вы можете использовать flutterRoot в других частях вашего файла настроек
// Она будет доступна в области видимости скрипта настроек

Лучшие практики для конфигурации Flutter Gradle

1. Следование официальным шаблонам Flutter

Документация Flutter показывает рекомендуемый подход для обработки путей к SDK Flutter:

kotlin
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. Обработка ошибок

Всегда включайте правильную обработку ошибок при чтении свойств:

kotlin
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. Порядок конфигурации репозиториев

Настраивайте репозитории в правильном порядке - сначала локальные, затем удаленные:

kotlin
repositories {
    mavenLocal()  // Если у вас есть локальные плагины
    maven(url = File(flutterRoot, "packages/flutter_tools/gradle/flutter_plugin_loader_repo").toURI())
    google()
    mavenCentral()
    gradlePluginPortal()
}

Устранение распространенных проблем

1. Ошибки “Файл не найден”

Если вы сталкиваетесь с ошибками, связанными с файлами, убедитесь, что файл local.properties существует и имеет правильный путь:

bash
flutter config --android-sdk <путь-к-vour-sdk>

2. Проблемы с разрешением репозиториев

Если плагины не могут быть разрешены, проверьте конфигурацию репозиториев:

kotlin
settingsEvaluated { settings ->
    settings.pluginManagement.resolutionStrategy {
        eachPlugin {
            // При необходимости принудительно используйте конкретные версии
            when (requested.id.id) {
                "com.android.application" -> useVersion("8.3.0")
            }
        }
    }
}

3. Синтаксические ошибки Kotlin DSL

Убедитесь, что вы используете правильный синтаксис Kotlin DSL:

kotlin
// Правильно
maven(url = File(flutterRoot, "path/to/repo").toURI())

// Неправильно
maven { url = "$flutterRoot/path/to/repo" }

Ключевой вывод заключается в том, что в файлах настроек Gradle Kotlin DSL переменные должны быть определены в той же области видимости, где они используются. Для блоков pluginManagement это означает определение переменных непосредственно внутри этого блока, а не на верхнем уровне файла.

Источники

  1. Gradle Kotlin DSL Primer - Официальная документация
  2. Документация Android Gradle Plugin Flutter
  3. Форумы Gradle: Обсуждение области видимости переменных Kotlin DSL
  4. Stack Overflow: Неопределенная ссылка в Settings Gradle KTS
  5. Документация по конфигурации плагинов Flutter

Заключение

Ошибка “Unresolved reference: flutterRoot” является распространенной проблемой при работе с Gradle Kotlin DSL в проектах Flutter. Решение заключается в понимании ограничений области видимости переменных и определении переменных в соответствующей области видимости. Переместив определение переменной flutterRoot внутрь блока pluginManagement, вы гарантируете ее доступность там, где это необходимо. Всегда следуйте официальным шаблонам Flutter и включайте правильную обработку ошибок для надежной конфигурации. Помните, что в settings.gradle.kts область видимости переменных строго ограничена местом их определения, поэтому планируйте свою конфигурацию соответствующим образом.