-
Notifications
You must be signed in to change notification settings - Fork 29.2k
Description
Gradle (the build system used for Android apps) has an awkwardly strict dependency on the version of Java it runs on: if you try to run a moderately old Gradle on a new JDK, the build will fail. Moreover it will do so with a totally inscrutable error.
This is about to become a problem for lots of Flutter developers, because the Gradle version that flutter create
would set up until recently is incompatible with the JDK version that lots of developers are going to be upgraded to in a couple of months. Many of them will not realize their JDK was upgraded. Because the Gradle error message is so bad, they will have a frustrating day of debugging, of StackOverflow questions, and likely of taking part in a flood of reports and comments in the Flutter issue tracker.
I think the only feasible way to avoid that flood of frustration is probably to write a migration (like these and these) to upgrade existing projects from the Gradle versions flutter create
would have chosen in the past to the version flutter create
would choose today.
Problem details
The exact Gradle version to use is encoded in a project's tree, at android/gradle/wrapper/gradle-wrapper.properties
.
Up until #99723, less than a year ago, the default from flutter create
was Gradle 6.7. So any project created before then is using that version or older, unless it's had an upgrade to the Gradle version.
Starting with Android Studio 2022.2 "Flamingo", the JDK bundled with Android Studio will switch from JDK 11 to JDK 17. That Android Studio version is currently in beta. It will presumably become the new stable in approximately May — at which point developers running existing Android Studio stable versions will start getting prompts to upgrade to it, and large numbers of them will do so.
(Compare the sudden flood of comments on #106674, the last major issue triggered by an Android Studio upgrade, starting on Jan 12. That was the release date of 2022.1 "Electric Eel" to stable.)
Whatever JDK comes bundled with Android Studio becomes the JDK that the flutter
tool uses by default. In doing so, the tool is faithfully following the recommendation from Android upstream. Many developers, following that same advice, will not even have any other JDK installation lying around.
And Gradle 6.7 is incompatible with JDK 17. So is any other version before Gradle 7.3. If you try to run an older Gradle with that newer JDK, you get an error like this:
FAILURE: Build failed with an exception.
* Where:
Build file '…/example/android/build.gradle'
* What went wrong:
Could not compile build file '…/example/android/build.gradle'.
> startup failed:
General error during conversion: Unsupported class file major version 61
java.lang.IllegalArgumentException: Unsupported class file major version 61
at groovyjarjarasm.asm.ClassReader.<init>(ClassReader.java:189)
at groovyjarjarasm.asm.ClassReader.<init>(ClassReader.java:170)
[…
…
… 209 more lines of Groovy and Gradle stack trace …
…
…]
at java.base/java.lang.Thread.run(Thread.java:833)
Putting it together: anyone who created a project with flutter create
from a Flutter older than last May's Flutter 3.0, and hasn't manually upgraded the version of Gradle it uses, will get the inscrutable error above the next time they attempt flutter run
or flutter build
for Android after they acquiesce to Android Studio's next round of self-upgrade prompts in a couple of months.
Alternate solutions
There are a couple of things we could do to help people choose a JDK independent of their upgrading Android Studio:
- Tool uses bundled JDK from Android Studio, contrary to Android Studio config #121501
- explicitly set java binary path with flutter config #106416
I think we ideally should do those things, on their own merits, but I don't think they really solve this problem. At best, they can only help when the developer knows that what they need is to use another JDK. Because that Gradle error message is so bad, and because the JDK upgrade will have happened as a side effect of upgrading Android Studio, that's already not easy to figure out.
Workarounds
The existing workarounds I know of are:
- Upgrade Gradle in your project. This is by far the preferred option. Once you've reached the point that you know this is what you need, and once you've worked out the steps involved in an upgrade, it's generally a pretty small and painless change.
- Don't upgrade Android Studio past 2022.1 "Electric Eel".
- Keep an Android Studio "Electric Eel" installation (or older) lying around, even while using a newer version. Then use
flutter config --android-studio-dir=…
to tell Flutter to look at that Android Studio installation, instead of the newer one, when looking for a JDK.
Why isn't this a problem for Android in general?
If you open an Android project in Android Studio, you get regularly prompted to upgrade Gradle and the Android Gradle Plugin, any time your project isn't already using the latest stable versions. Android Studio provides a slick UI for doing so, too. So anyone working directly in Android will have had ample notice and opportunity to take this upgrade already.
If you open a Flutter project in Android Studio, however, there's no such prompt, even when the project has an android/
folder with an Android build. It's only if you open that android/
folder as its own project that you get Android-specific prompts, including those for the Gradle upgrade. If you're happily writing pure Dart code, and not regularly digging into the Android platform side, you may never have cause to see them.
Other related issues
-
Most of the example apps in flutter/packages need this upgrade: [packages] Run AGP update on all examples #122213
(So do apps in
dev/integration_tests/
in flutter/flutter, and apps in the flutter/platform_tests repo.)
Steps to Reproduce
See the repro steps in #121501. For this issue, only steps 1-4 are needed.
For step 3, instead of going to an existing Flutter project that's using an older Gradle version, one can make the point sharper (for this issue) by running flutter create
using Flutter 2.10.5 or older. See #121501 (comment) .