Skip to main content

Troubleshooting Gradle 8 & Java 17 Incompatibility in Flutter Android Builds

 You open an existing Flutter project, perhaps one you haven't touched in a few months, or clone a repo that hasn't been updated recently. You hit "Run," and instead of the familiar Gradle build tasks, the console crashes immediately with a cryptic error:

java.lang.IllegalArgumentException: Unsupported class file major version 61

Or perhaps:

Could not create service of type ScriptPluginFactory using BuildScopeServices.createScriptPluginFactory().
> Unsupported class file major version 65

This error is not a bug in your Dart code. It is an infrastructure collision between your IDE, the Java Development Kit (JDK), and the Gradle build tool.

The Root Cause: Bytecode Mismatch

The error "Unsupported class file major version" is the JVM's way of saying, "I am trying to read a class file compiled with a newer version of Java than I support."

Here is the mapping you need to know:

  • Version 55 = Java 11
  • Version 61 = Java 17
  • Version 65 = Java 21

The collision happens due to the evolution of Android Studio. Recent versions (Flamingo, Giraffe, Iguana, Koala) bundle JDK 17 (and lately JDK 21) as the default Gradle daemon runtime.

However, older Flutter projects usually ship with a gradle-wrapper.properties file pointing to Gradle 7.x (or older).

The incompatibility matrix:

  • Gradle 7.2 (and below) cannot run on JDK 17.
  • Gradle 7.5 (and below) cannot run on JDK 20/21.

When you press run, Android Studio launches the Gradle Daemon using its internal JDK (Java 17/21). That daemon attempts to spin up the Gradle Wrapper defined in your project (e.g., Gradle 7.0). The wrapper crashes because it doesn't understand the JVM version running it.

The Solution: Modernize the Build Chain

While you can downgrade the JDK used by Android Studio, that is a temporary patch. The correct engineering solution is to upgrade your project's build infrastructure to support Java 17.

This involves three specific files in your android directory.

1. Upgrade the Gradle Wrapper

First, tell the project to use a version of Gradle that supports modern Java. We will use Gradle 8.5, which is stable and performant.

File: android/gradle/wrapper/gradle-wrapper.properties

Update the distributionUrl to point to version 8.5.

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
# Change this line:
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip

2. Upgrade the Android Gradle Plugin (AGP)

The AGP version acts as the bridge between Gradle and the Android build system. Gradle 8.5 requires AGP version 8.1.0 or higher.

File: android/build.gradle (Project Level)

Locate the buildscript block or the plugins block (depending on your project age) and update the dependency version.

buildscript {
    ext.kotlin_version = '1.9.22' // Ensure Kotlin is also reasonably modern
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        // Update to 8.1.0 or higher
        classpath 'com.android.tools.build:gradle:8.2.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

tasks.register("clean", Delete) {
    delete rootProject.buildDir
}

3. Configure Java 17 Compatibility & Namespace

Finally, you must explicitly tell the compiler to generate bytecode compatible with Java 17. Additionally, AGP 8.0+ enforces the removal of the package attribute from the AndroidManifest.xml in favor of a namespace declaration in the build file.

File: android/app/build.gradle (Module Level)

plugins {
    id "com.android.application"
    id "kotlin-android"
    // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
    id "dev.flutter.flutter-gradle-plugin"
}

android {
    // 1. Define the namespace (Replaces 'package' in AndroidManifest.xml)
    namespace "com.example.your_app_name" 
    
    compileSdk 34 // Target Android 14

    defaultConfig {
        applicationId "com.example.your_app_name"
        minSdk 21 // Flutter default minimum
        targetSdk 34
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    // 2. Configure Compile Options for Java 17
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }

    // 3. Configure Kotlin Options
    kotlinOptions {
        jvmTarget = '17'
    }

    buildTypes {
        release {
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

4. Verification

After making these changes, perform a clean build to flush the cache of the old incompatible artifacts.

Run the following in your terminal:

cd android
./gradlew clean
cd ..
flutter pub get
flutter run

Why This Fix Works

  1. Gradle 8.5 Alignment: By upgrading the wrapper to 8.5, you use a build tool version that is natively compiled against and tested with JDK 17+. It no longer crashes when the Android Studio daemon (running JDK 17) invokes it.
  2. AGP Compatibility: The Android Gradle Plugin version must always move in lockstep with the Gradle version. AGP 8.x is designed for Gradle 8.x and utilizes the R8 full-mode compiler by default, resulting in smaller APK sizes.
  3. JVM Target 17: Setting sourceCompatibility and jvmTarget ensures that when your Android/Kotlin code is compiled, the resulting bytecode header contains the major version "61". This matches the runtime environment provided by modern Android devices and the build environment provided by Android Studio.

By aligning your toolchain (IDE JDK), your build orchestrator (Gradle), and your compiler settings (AGP), you eliminate the version drift that causes the "Unsupported class file major version" error.