Files
flutter-android-template/README.md
T
mikkeli 557b2d92a5 Initial template: Flutter 3.47.1 Android app, verified building
`flutter create --platforms android` output, unmodified except for docs and one
commented-out escape hatch. The generated toolchain is already what we want --
Gradle 9.3.1 / AGP 9.1.0 / Kotlin 2.4.0 / Java 17 -- because Flutter's template
defaults ARE the policy: they sit above the warn floor, where the floors-only
combo sits one release from breaking.

The point of this repo is the notes, not the code. README.md records why two
apps in this org stopped building without their code changing, where Flutter
keeps its version floors (read them, do not recall them), and four traps that
appear in no changelog: the pub-cache edit that hides from git, kotlinOptions{}
being a compilation error rather than a deprecation under Kotlin >= 2.3, AGP 8.x
being unable to run on Gradle >= 9.6, and Built-in Kotlin being a dead end while
AGP ships a Kotlin below Flutter's own floor.

android/build.gradle.kts carries a commented-out subprojects{} override for
abandoned pub plugins whose declared compileSdk their own AndroidX dependencies
now reject. Off by default: turn it on when a build fails, not speculatively.

Verified: flutter build apk --debug and --release against Flutter 3.47.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dKAqFo9Uj3mPZWvDzj3G8
2026-08-23 12:02:51 +09:00

101 lines
4.8 KiB
Markdown

# 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.