Start Debugging

Ein Flutter-Android-Projekt auf AGP 9 mit Built-in Kotlin migrieren

Der vollständige Weg von einer AGP-8-Flutter-App, die kotlin-android anwendet, zu AGP 9.1 mit android.builtInKotlin=true auf Flutter 3.47. Jeder Schritt wurde gebaut und gemessen, einschließlich der zwei Änderungen, die optional aussehen und es nicht sind: kotlinOptions ist unter KGP 2.2+ ein Kompilierfehler, und die KGP-Zeile in settings.gradle.kts muss bleiben.

Für eine Flutter-App, die vor Flutter 3.44 erstellt wurde, besteht die Migration aus vier Änderungen: den Gradle Wrapper auf 9.3.1 und AGP auf 9.1.0 anheben, die Version des Kotlin Gradle Plugin (KGP) in settings.gradle.kts auf 2.4.0 anheben, die Zeile aber behalten, kotlinOptions durch einen kotlin { compilerOptions { ... } }-Block auf oberster Ebene ersetzen und id("kotlin-android") aus app/build.gradle.kts löschen. Danach setzen Sie android.builtInKotlin=true in gradle.properties, was Flutter 3.47 oder neuer voraussetzt, und zwar erst, wenn jedes Plugin, von dem Sie abhängen, ebenfalls auf KGP verzichtet. Planen Sie für eine App mit aktuellen Abhängigkeiten eine Stunde ein, länger, wenn ein Plugin noch kotlin-android anwendet. Es lohnt sich, das jetzt zu erledigen: Flutter verweigert bereits den Build mit Gradle unter 8.14 oder AGP unter 8.11.1 und hat angekündigt, die KGP-Unterstützung vollständig zu entfernen (flutter#184837).

Alles Folgende lief auf Flutter 3.47.4 stable (Framework-Revision 9584c6713b, Dart 3.13), OpenJDK 17.0.20 und Android SDK build-tools 36.1, ausgehend von einem Projekt, das genau wie das android-kotlin-Template von Flutter 3.35 aufgebaut war: AGP 8.9.1, KGP 2.1.0, Gradle 8.12, id("kotlin-android") im App-Modul und ein kotlinOptions-Block. Den Endzustand habe ich zusätzlich auf Flutter 3.44.8 geprüft. Zu jedem Schritt steht die exakte Ausgabe, die ich bekommen habe.

Warum diese Migration nicht mehr optional ist

Was kaputtgeht

BereichÄnderungSchweregrad
Gradle WrapperFlutter 3.47 bricht unter 8.14 ab; AGP 9.1 braucht 9.3.1hoch
kotlin-android im App-ModulScheitert mit aktiviertem Built-in Kotlinhoch
kotlinOptions { jvmTarget = ... }Fehler bei der Skriptkompilierung unter KGP 2.2 und neuerhoch
Plugins, die KGP anwendenLassen Ihren Build scheitern, sobald android.builtInKotlin=true gilthoch
android.newDsl=trueDas Flutter Gradle Plugin castet noch auf die alte DSL, ClassCastExceptionhoch (auf false lassen)
KGP-Eintrag in settings.gradle.ktsEntfernen fällt auf das mit AGP gebündelte Kotlin 2.2.10 zurück, unter Flutters Mindestversionmittel
build.gradle-Projekte (Groovy)Dieselben Änderungen, andere Syntax; buildscript-Layouts vor 3.16 brauchen zuerst die Migration auf deklarative Pluginsmittel

Checkliste vor dem Start

Migrationsschritte

  1. Lassen Sie das Flutter-Tool die beiden Opt-out-Flags hinzufügen und prüfen Sie sie dann. Führen Sie einmal einen beliebigen Android-Build mit Flutter 3.44 oder neuer aus. Die Migratoren des Tools hängen beide Flags an android/gradle.properties an, falls sie fehlen. Bei meinem Projekt scheiterte der Build trotzdem (wegen Gradle 8.12), aber die Datei war bereits umgeschrieben:

    # android/gradle.properties, written by the Flutter 3.47.4 migrators
    org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
    android.useAndroidX=true
    # This builtInKotlin flag was added automatically by Flutter migrator
    android.builtInKotlin=false
    # This newDsl flag was added automatically by Flutter migrator
    android.newDsl=false

    Bei Add-to-App-Host-Projekten läuft der Migrator nie, weil der Host ein reines Android-Projekt ist. Dort tragen Sie beide Zeilen von Hand in die gradle.properties des Hosts ein. Prüfen: grep -E 'builtInKotlin|newDsl' android/gradle.properties gibt beide Zeilen aus.

  2. Heben Sie den Gradle Wrapper auf 9.3.1 an. AGP 9.0.x braucht Gradle 9.1.0 oder neuer, und Flutters Tooling kombiniert AGP 9.1.x mit 9.3.1 oder neuer, was auch das Template von Flutter 3.47 mitbringt:

    # android/gradle/wrapper/gradle-wrapper.properties, Flutter 3.47.4
    distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip

    Prüfen: cd android && ./gradlew --version meldet Gradle 9.3.1.

  3. Heben Sie AGP und KGP in settings.gradle.kts an und behalten Sie die Kotlin-Zeile. Das sind die Versionen, die flutter create in 3.47.4 schreibt:

    // android/settings.gradle.kts, Flutter 3.47.4, AGP 9.1.0, KGP 2.4.0
    plugins {
        id("dev.flutter.flutter-plugin-loader") version "1.0.0"
        id("com.android.application") version "9.1.0" apply false
        id("org.jetbrains.kotlin.android") version "2.4.0" apply false
    }

    Es ist verlockend, die Zeile org.jetbrains.kotlin.android zu löschen, da der Sinn der Migration ja ist, KGP nicht mehr zu verwenden. Tun Sie es nicht. Mit apply false legt sie nur diese Kotlin-Version auf den Build-Classpath, und Built-in Kotlin kompiliert damit. Als ich sie entfernt habe, fiel AGP 9.1.0 auf sein gebündeltes Kotlin 2.2.10 zurück, und das Flutter Gradle Plugin lehnte den Build ab: Your project's Kotlin version (2.2.10) is lower than Flutter's minimum supported version of 2.2.20. Die Zeile ist auch wichtig, solange builtInKotlin=false gilt, denn dann wendet das Flutter Gradle Plugin kotlin-android selbst auf jedes Android-Unterprojekt an, das es nicht tut, und dafür braucht es KGP auf dem Classpath.

    Prüfen: noch nichts. Der Build scheitert bis Schritt 4 weiterhin.

  4. Ersetzen Sie kotlinOptions durch die compilerOptions-DSL. Das ist die Änderung, die viele überrascht, weil sie nötig ist, noch bevor Sie Built-in Kotlin anfassen. Mit AGP 9.1.0, KGP 2.4.0, weiterhin angewendetem kotlin-android und builtInKotlin=false scheiterte mein Build bei der Skriptkompilierung:

    Script compilation errors:
      Line 18:     kotlinOptions {
                   ^ 'fun BaseAppModuleExtension.kotlinOptions(configure: Action<DeprecatedKotlinJvmOptions>): Unit' is deprecated. Please migrate to the compilerOptions DSL.
      Line 19:         jvmTarget = JavaVersion.VERSION_11.toString()
                       ^ 'var jvmTarget: String' is deprecated. Please migrate to the compilerOptions DSL.

    Kotlin 2.2.0 hat die Deprecation von kotlinOptions zu einem Fehler hochgestuft, und Flutter 3.47 lässt Sie nicht unter KGP 2.2.20 bleiben, also gibt es keine Versionskombination, in der kotlinOptions überlebt. Verschieben Sie das JVM-Target aus dem android {}-Block in einen kotlin {}-Block auf oberster Ebene:

    // android/app/build.gradle.kts, Flutter 3.47.4, AGP 9.1.0, KGP 2.4.0
    android {
        // ...
        compileOptions {
            sourceCompatibility = JavaVersion.VERSION_17
            targetCompatibility = JavaVersion.VERSION_17
        }
        // kotlinOptions { jvmTarget = JavaVersion.VERSION_17.toString() }  <- delete
    }
    
    kotlin {
        compilerOptions {
            jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
        }
    }

    Halten Sie jvmTarget gleich targetCompatibility. Alte Templates nutzten 11, neue nutzen 17; beides funktioniert, solange die zwei übereinstimmen. Prüfen: flutter build apk --debug ist erfolgreich. An diesem Punkt gibt es außerdem WARNING: Your Android app project: app ... applies the Kotlin Gradle Plugin, which will cause build failures in future versions of Flutter. aus. Diese Warnung ist erwartet, und genau sie entfernt Schritt 5.

  5. Entfernen Sie kotlin-android aus dem App-Modul. Löschen Sie die Plugin-Zeile und sonst nichts:

    // android/app/build.gradle.kts, Flutter 3.47.4
    plugins {
        id("com.android.application")
        // id("kotlin-android")  <- delete
        // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
        id("dev.flutter.flutter-gradle-plugin")
    }

    Nutzt Ihr App-Modul die Version-Catalog-Form, ist die zu löschende Zeile alias(libs.plugins.kotlin.android). Bei einer Groovy-build.gradle ist es apply plugin: 'kotlin-android' oder id "kotlin-android", und der kotlin { compilerOptions { ... } }-Block aus Schritt 4 ist so, wie er dasteht, gültiges Groovy. Prüfen: flutter build apk --debug ist erfolgreich, ohne KGP-Warnung für app. Da builtInKotlin noch auf false steht, wendet jetzt das Flutter Gradle Plugin KGP in Ihrem Namen an, weshalb dieser Zwischenzustand baut.

  6. Finden Sie die Plugins, die noch KGP anwenden. Bauen Sie noch einmal mit builtInKotlin=false und lesen Sie die Gradle-Ausgabe. Flutter 3.47 nennt sie Ihnen:

    WARNING: Your app uses the following plugins that apply Kotlin Gradle Plugin (KGP): oldplug
    Future versions of Flutter will fail to build if your app uses plugins that apply KGP.
    Please check the changelogs of these plugins and upgrade to a version that supports Built-in Kotlin.

    Suchen Sie für jedes aufgeführte Plugin auf pub.dev nach einer neueren Version, deren Changelog Built-in Kotlin oder AGP 9 erwähnt, und aktualisieren Sie. Gibt es keine, eröffnen Sie ein Issue beim Plugin (Flutters Leitfaden für App-Entwickler enthält eine Issue-Vorlage) und hören Sie hier auf: Sie sind auf AGP 9 mit deaktiviertem Built-in Kotlin, was ein unterstützter Zustand ist. Prüfen: Die Warnung listet kein Plugin mehr auf.

  7. Aktivieren Sie Built-in Kotlin. Erst wenn Schritt 6 sauber zurückkommt:

    # android/gradle.properties, Flutter 3.47.4, AGP 9.1.0
    android.builtInKotlin=true
    android.newDsl=false

    Lassen Sie android.newDsl=false stehen. Prüfen: flutter build apk --debug ist ohne KGP-Warnungen erfolgreich, und danach startet flutter run die App auf einem Gerät oder Emulator.

Checkliste zur Überprüfung

Rollback-Plan

Die Migration ist in jedem Schritt umkehrbar, und das günstigste Rollback ist ein teilweises. Wenn nach Schritt 7 ein Plugin kaputtgeht, setzen Sie android.builtInKotlin=false wieder: Mit diesem Flag akzeptiert AGP 9 KGP, und das Flutter Gradle Plugin wendet kotlin-android erneut auf die Module an, die es brauchen, sodass Sie die kotlin-android-Zeile in Ihrem App-Modul nicht wiederherstellen müssen. Ein vollständiges Rollback auf AGP 8 bedeutet, settings.gradle.kts und den Wrapper aus git wiederherzustellen, aber auf Flutter 3.47 können Sie nicht unter AGP 8.11.1, Gradle 8.14 oder KGP 2.2.20 gehen, also bedeutet “Rollback” in Wahrheit AGP 8.11+, nicht Ihr ursprüngliches 8.9. Die Änderung kotlin { compilerOptions } aus Schritt 4 bleibt in jedem Fall.

Stolperfallen, auf die ich unterwegs gestoßen bin

Der erste Fehler hat überhaupt nichts mit Kotlin zu tun. Beim nicht migrierten Projekt gab Flutter 3.47.4 das eigentliche Problem (Gradle 8.12 unter 8.14) innerhalb der Gradle-Ausgabe aus und darunter einen umrahmten “Flutter Fix”, der Starting AGP 9+, only the new DSL interface will be read meldete und vorschlug, sich per Opt-out von android.newDsl abzumelden. Das Projekt lief auf AGP 8.9.1. Der Kasten ist eine Heuristik, die bei jedem Fehlschlag beim Anwenden des Flutter Gradle Plugin auslöst, also lesen Sie zuerst den Abschnitt * What went wrong:, derselbe Rat wie im Leitfaden zu assembleDebug mit Exit-Code 1.

Die Fehlermeldung für ein übrig gebliebenes kotlin-android hängt von Ihrer KGP-Version ab. Mit KGP 2.4.0 ist sie eindeutig:

> Failed to apply plugin 'kotlin-android'.
   > ⛔ Failed to apply plugin 'org.jetbrains.kotlin.android'
     The 'org.jetbrains.kotlin.android' plugin is no longer required for Kotlin support since AGP 9.0.
     Solution: Remove the 'org.jetbrains.kotlin.android' plugin from this project's build file: app/build.gradle.kts.

Mit älteren KGP-Versionen zeigt sich derselbe Fehler als Cannot add extension with name 'kotlin', die Form, die die meisten Antworten auf Stack Overflow zitieren. Die Zeile Solution: ist nützlich, wenn der Übeltäter ein Plugin ist: Bei meinem Test-Plugin zeigte sie auf ../../oldplug/android/build.gradle.kts. Bei einem pub.dev-Paket zeigt der Pfad in ~/.pub-cache/hosted/pub.dev/<package>-<version>/android/, was Ihnen genau sagt, welches Paket Sie aktualisieren müssen. Bearbeiten Sie keine Dateien im Pub-Cache; sie werden beim nächsten pub get überschrieben.

android.newDsl=true ist weiterhin ein harter Fehler. Mit allem anderen migriert führte das Setzen zu class com.android.build.gradle.internal.dsl.ApplicationExtensionImpl$AgpDecorated_Decorated cannot be cast to class com.android.build.gradle.AbstractAppExtension. Das Flutter Gradle Plugin liest noch die alten DSL-Typen (flutter#180137 verfolgt die Portierung). Lassen Sie das Flag auf false, bis ein Flutter-Release etwas anderes sagt, und rechnen Sie damit, dass dieses Release vor AGP 10 erscheint.

Flutter 3.44 funktioniert mit aktiviertem Built-in Kotlin nur halb. Die Dokumentation sagt, dass android.builtInKotlin=true 3.47 braucht. Ich habe das vollständig migrierte Projekt trotzdem auf Flutter 3.44.8 laufen lassen: Das APK wurde gebaut und MainActivity war im Dex, aber das Tool gab Applying the Kotlin Android Plugin (KGP) was unsuccessful. KGP was not found on the classpath. aus. Das kommt vom Flutter Gradle Plugin aus 3.44, das das Flag nicht liest und trotzdem versucht, KGP anzuwenden. In einer trivialen App ist das harmlos und in einem CI-Log verwirrend, also behandeln Sie 3.47 als das echte Minimum, genau wie dokumentiert.

Projekte vor 3.16 brauchen zuerst eine frühere Migration. Wenn Ihre android/build.gradle noch buildscript { ext.kotlin_version = '...' } enthält und Ihr App-Modul apply from: ".../flutter.gradle" verwendet, lassen sich die obigen Schritte nicht sauber übertragen. Führen Sie zuerst die Migration auf deklarative Plugins durch und kehren Sie dann zu Schritt 2 zurück. Dieses Layout habe ich für diesen Beitrag nicht nachgestellt; dort ist die Flutter-Dokumentation die Referenz. Wenn Sie stattdessen an der alten Meldung zur Kotlin-Version hängen, erklärt der Beitrag zum KGP-Versionsfehler, wo diese Version in älteren Layouts steht.

Gradle 9 macht andere alte Warnungen zu Fehlern. Gradle 9 hat APIs entfernt, die Gradle 8 nur als veraltet markiert hatte, sodass ein altes Plugin aus Gründen scheitern kann, die nichts mit Kotlin zu tun haben. Taucht daneben eine JDK-24-Warnung wie A restricted method in java.lang.System has been called auf, wird diese in einem eigenen Beitrag behandelt.

Gemessene Ergebnisse

Projektzustand (Flutter 3.47.4, sofern nicht anders angegeben)Ergebnis
AGP 8.9.1, KGP 2.1.0, Gradle 8.12, kotlin-androidScheitert: Gradle unter 8.14
AGP 9.1.0, KGP 2.4.0, Gradle 9.3.1, kotlinOptions behaltenScheitert: Fehler bei der Skriptkompilierung
Dasselbe, compilerOptions, kotlin-android behalten, builtInKotlin=falseBaut, KGP-Warnung für app
Dasselbe, builtInKotlin=trueScheitert: KGP seit AGP 9.0 nicht mehr erforderlich
kotlin-android entfernt, builtInKotlin=trueBaut, 4,0 s inkrementell
KGP-Zeile aus settings.gradle.kts entferntScheitert: Kotlin 2.2.10 unter 2.2.20
Plugin wendet KGP an, builtInKotlin=trueScheitert, nennt die Build-Datei des Plugins
Plugin wendet KGP an, builtInKotlin=falseBaut, Warnung listet das Plugin auf
Migriert, newDsl=trueScheitert: ClassCastException im Flutter Gradle Plugin
Migriert, builtInKotlin=true, Flutter 3.44.8Baut, irreführende Meldung “KGP was not found”

Verwandte Beiträge

Quellen

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Zurück