НейроАгент

Flutter Gradle KTS: Как исправить ошибку 'Unresolved reference: flutterRoot'

Полное руководство по устранению ошибки 'Unresolved reference: flutterRoot' в файле settings.gradle.kts при настройке pluginManagement в проектах Flutter.

Вопрос

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:

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” будут очень признательны.

НейроАгент

Ошибка “Unresolved reference: flutterRoot”

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

Содержание

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

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

Как объясняется в обсуждениях на форумах Gradle, это распространенная проблема при миграции между версиями Gradle, особенно с версии 5.x на 6.x и более поздние, где правила области видимости стали более строгими.

Проблема возникает потому, что Gradle оценивает блок pluginManagement на ранней фазе конфигурации, до того как получает доступ к переменным, определенным в основной области видимости скрипта.

Решение 1: Перемещение переменных внутрь pluginManagement

Наиболее прямое решение - переместить определения переменных непосредственно внутрь блока pluginManagement, где они нужны:

kotlin
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 для обеспечения доступности переменных во всем файле настроек:

kotlin
// Определяем свойства на верхнем уровне
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, можно использовать провайдеры:

kotlin
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")

Этот подход более надежен и обрабатывает разрешение свойств отложенным образом.

Полная рабочая конфигурация

Вот полная рабочая конфигурация, решающая проблему области видимости:

kotlin
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

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

  1. Используйте синтаксис Plugin DSL: Как указано в документации Flutter, перейдите от императивного синтаксиса apply plugin: к современному синтаксису plugins { id ... }.

  2. Обеспечьте совместимость версии Gradle: Ошибки “Unresolved reference” часто вызваны использованием устаревшей версии Gradle. Убедитесь, что вы используете Gradle 6.8 или более позднюю версию для поддержки dependencyResolutionManagement.

  3. Организуйте ваш settings.gradle.kts: Держите связанные конфигурации вместе и используйте соответствующую область видимости, чтобы избежать ошибок ссылок.

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

  5. Используйте правильную обработку ошибок: Предоставляйте осмысленные сообщения об ошибках, когда требуемые свойства отсутствуют.

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

Если вы столкнетесь с аналогичными проблемами, рассмотрите следующие дополнительные шаги по устранению неполадок:

  1. Проверьте версию Gradle wrapper: Убедитесь, что ваш gradle-wrapper.properties использует совместимую версию.

  2. Обновите Android Gradle Plugin: Убедитесь, что вы используете совместимую версию Android Gradle Plugin.

  3. Очистите и пересоберите: Иногда простая очистка проекта и пересборка может решить проблемы конфигурации.

  4. Проверьте наличие устаревшего синтаксиса: Удалите все устаревшие операторы apply plugin: и используйте современный plugin DSL.

  5. Проверьте версии плагинов: Убедитесь, что все версии плагинов совместимы друг с другом и с вашей версией Flutter.

Ключевой вывод заключается в том, что Gradle Kotlin DSL имеет определенные правила области видимости, и переменные должны быть определены в соответствующей области видимости, где они используются. Перемещая разрешение пути к SDK Flutter внутрь блока pluginManagement, вы можете устранить ошибку “Unresolved reference: flutterRoot” и успешно настроить свой Flutter проект с Deferred Components.

Источники

  1. Руководство по миграции Flutter Gradle Plugin
  2. Форумы Gradle - Неопределенные ссылки в settings.gradle.kts
  3. Stack Overflow - Неопределенная ссылка: dependencyResolutionManagement
  4. Проблема Gradle #34145 - Неопределенная ссылка pluginManagement
  5. 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.