# flutter-android-template Starting point for Flutter Android apps on **halogen**. Generated by `flutter create` and then annotated — the value here is not the code, it is the notes on the parts that go wrong six months later. Generated **2026-08-23** against **Flutter 3.47.1**, verified `--debug` and `--release`. ## Use it Gitea template repo — *Use this template* on the web UI, or: ```bash tea repos create --owner android-stuff --name my-app # then, locally: flutter create --org com.novoyuuparosk --project-name my_app --platforms android . ``` After cloning, before anything else: ```bash flutter-android-preflight . # on halogen; see below flutter pub get flutter build apk --debug ``` `android/local.properties` is gitignored and regenerated per machine. Do not commit it. ## Why this repo exists Two apps in this org became unbuildable without a line of their code changing. They had been pinned to Gradle 8.12 / AGP 8.9.1 / Kotlin 2.1.0 — fine when written, and by 2026-08-23 all three were **below the hard floors Flutter refuses to build under**. Flutter carries those floors as source constants inside the SDK, and moves them every release: | | | |---|---| | `packages/flutter_tools/gradle/src/main/kotlin/DependencyVersionChecker.kt` | error + warn floors for Gradle / AGP / Kotlin / Java / minSdk | | `packages/flutter_tools/lib/src/android/gradle_utils.dart` | template defaults, compileSdk, NDK | **Read those two files instead of recalling version numbers.** Any remembered number is wrong on a long enough timeline, including one you read in a blog post last week. ## The rule that keeps this from happening again > **Track Flutter's template defaults, not its floors.** Flutter promotes its `warn` floor to the `error` floor in the very next release — its own source says so. A project sitting just above the *hard* floor has one release of runway before it breaks. A project on the template defaults has the full cycle. That is why this template is on Gradle 9.3.1 / AGP 9.1.0 / Kotlin 2.4.0 / Java 17 rather than the lower combo that merely builds today. `/usr/local/bin/flutter-android-preflight` on halogen automates the comparison: it parses the floors out of the *installed* SDK, checks a project against them, and `--fix` rewrites the project. Run it **after every `flutter upgrade`**, not when a build breaks. `/opt/flutter` tracks the `stable` branch, so it moves on its own. ## Traps, none of which are in a changelog - ⚠ **Never edit `~/.pub-cache`.** It is shared between users, unversioned, invisible to `git status`, and wiped by the next `pub get`. An edit there poisons every build on the machine and leaves no trace in any repo. If a plugin needs different build settings, override them from `android/build.gradle.kts` — there is a worked example, commented out, in that file. Damage is repaired with `dart pub cache repair --all`. - ⚠ **`kotlinOptions {}` is a script COMPILATION ERROR under Kotlin ≥ 2.3**, not a deprecation warning. Use `kotlin { compilerOptions { jvmTarget = ... } }`, as `android/app/build.gradle.kts` here already does. - ⚠ **AGP 8.x cannot run on Gradle ≥ 9.6.** Gradle 9.6.0 removed `InternalProblems`, which every AGP 8.x builds against; Gradle 9.7 fails at configuration time. While on AGP 8.x, Gradle is capped at 9.5. Moot on AGP 9, but it is what makes "just use the newest Gradle" the wrong instinct. - ⚠ **Built-in Kotlin is a dead end on Flutter 3.47.1.** Flutter warns that applying the Kotlin Gradle Plugin "will cause build failures in future versions" and points at the migration guide. Do not follow it yet: with `android.builtInKotlin=true`, AGP 9.1.0 supplies **Kotlin 2.2.10**, which is *below Flutter's own 2.2.20 floor* — Flutter rejects the Kotlin that Flutter told you to adopt. Keep `builtInKotlin=false` and apply KGP explicitly until AGP ships a Kotlin at or above the SDK's floor. - **`android.enableJetifier`** is obsolete and removed outright in AGP 9. It is absent here deliberately; do not let an old snippet reintroduce it. - **Abandoned plugins are the residual risk.** The toolchain is now easy to keep current; a pub package last published in 2022 is not. Check `flutter pub outdated` before adopting a dependency that looks quiet. ## Shared toolchain on halogen `/opt/flutter` and `/opt/android-sdk` are group `flutterdev` (`mikkeli`, `hermes`) with default ACLs granting the group write. Gradle compiles the Flutter Gradle plugin **in place** inside the SDK, so without those ACLs whichever user builds first locks the other out — and the resulting error mentions nothing about permissions: ``` IllegalStateException: The settings are not yet available for build. ``` If that appears, check ownership under `/opt/flutter/packages/flutter_tools/gradle/{build,.gradle}` before believing anything else.