What I like LEAST about Flutter are "The Updates" + Tips

- Andrés Cruz - ES En español

Video thumbnail

What really bothers me about the Flutter ecosystem is Android, the damn updates.
 

I have a compulsion to keep everything up to date, and I run commands several times a week. I keep SDKs, packages, and Android Studio up to date. The problem is that from one day to the next, a project that was working stops working.

flutter upgrade

and others

For example, an academic project ran perfectly on Windows, but not on MacOS. It used to be the other way around: it worked on Mac, but not on Windows. And all this just because of version differences and updates.

Errors, versions, dependencies and more

  • These problems are often accompanied by very verbose errors. For example, on Windows, I had a conflict with a package (WYSIWYG editor), which was later updated. It's also happened to me with the Android SDK: versions 35 and 36 causing warnings and errors.
  • Often, I don't understand what's going on. I end up tracking files, checking internal project dependencies, mainly Gradle files, versioning with the Android SDK or the Flutter SDK, or pubspec.yaml or .lock.
  • Not to mention that internally, they update the Android project with different syntaxes or directly type files. An example of the latter is build.gradle.kts, whose Kotlin extension, kts in older versions, was not included.

It's very annoying because these aren't "old" projects, but relatively new ones. But updates make them incompatible. And here's the dilemma:

  • Or you try to update manually, praying you don't forget anything.
  • Or you create a new project in Flutter and start copying and pasting everything, running the risk of leaving something out (as happened to me once with AndroidManifest).
  • That's why I think there should be a command to update projects automatically. Doing it manually is tedious and time-consuming.

So in conclusion, the problem with Flutter isn't the coding or the programming language; the poison is carried internally by the project itself, as it doesn't update automatically as new updates are released for related technologies.

The Smart Way to Upgrade Flutter Without Breaking Your App

Video thumbnail

One of the most critical aspects when working with Flutter lies in managing its updates. Although it is a robust framework, the evolution of its versions often brings compatibility issues that can break an existing project. This phenomenon is not unique to Flutter; backend frameworks like Laravel also face similar challenges due to their rapid evolution, causing mismatches in applications that become outdated.

**To understand the root of this problem in Flutter, it is essential to analyze its internal architecture. Flutter allows developing a single codebase in Dart and exporting it natively to multiple platforms:** Android, iOS, Web, and desktop environments (Windows, Linux, and macOS). For this reason, a project's structure includes dedicated folders for each operating system (/android, /ios, /web, etc.). These folders are not mere containers; they house the native environments required for the final compilation.

The Dependence on Native Environments

Due to this architecture, Flutter obligatorily depends on specific tools from each platform to compile native code:

  • Android: Requires Android Studio, its SDK, Command Line Tools, and Gradle.
  • iOS: Requires Xcode and Apple development tools.
  • Windows: Requires specific Visual Studio modules (C++).

The real conflict arises because these native platforms evolve independently of Flutter. Taking Android as an example, the operating system constantly updates its SDK levels, Java versions, and build tools. When the Flutter SDK is updated using the flutter upgrade command, it is highly likely to break synchronization with the underlying native environment.

The Critical Role of Gradle in Android

In the Android ecosystem, the configuration and success of the build depend mainly on three files managed by Gradle. When a project is several months or years old, the versions of these files conflict with the guidelines of the new Flutter SDK:

  1. build.gradle (Android project root): Defines the repositories and global versions of Gradle plugins.
  2. build.gradle (/app directory): Specifies the versions of compileSdkVersion, minSdkVersion, and targetSdkVersion.
  3. gradle-wrapper.properties: Determines the exact version of the Gradle engine that the system will download to compile.

Historically, resolving these conflicts required a tedious trial-and-error process: searching for version compatibilities in official repositories, cleaning the project cache via flutter clean, or running native commands like gradlew clean. Furthermore, syntactic changes introduced in build tools —such as the transition from traditional Groovy-based configuration files to the modern KTS (Kotlin Script) format— elevate the complexity of manual maintenance.

Old:

android/build.gradle

allprojects {
    repositories {
        google()
        mainCentral()
    }
}

rootProject.buildDir = '../build'

Modern:

android/build.gradle.kts

allprojects {
    repositories {
        google()
        mainCentral()
    }
}

val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)

Solution and Mitigation Strategies

To resolve these desynchronizations without compromising development stability, three strategic approaches can be applied:

A. AI-Assisted Diagnosis

Currently, using language models facilitates the resolution of verbose compilation errors. By providing the full log of the error generated by Gradle to the AI, it usually identifies the exact incompatibility accurately and suggests the correct version ranges for the configuration files.

B. Selective Regeneration of the Native Folder (Recommended Approach)

Unless custom native code is being implemented, the /android folder is rarely modified manually, except for configurations in the AndroidManifest.xml file (internet permissions, AdMob keys, notification services, etc.). Therefore, an efficient solution consists of replacing the obsolete native structure with a clean one:

  • Secure current changes by performing a git commit or backup.
  • Rename the conflicting /android folder (for example, to /android_old) to keep it as a reference.
  • Generate a new Flutter project in a temporary directory using the same Package Name to inherit the updated and compatible /android folder from the new SDK.
  • Copy this clean folder to the original project and migrate only specific configuration lines (such as permissions from AndroidManifest.xml) from the old folder.

C. Full Migration to a Mirror Project

If replacing folders generates persistent dependency conflicts, the ultimate solution is to create a completely new project from scratch. Subsequently, a manual migration of the main source code directory (/lib) and dependency declarations inside the pubspec.yaml file is carried out, thus ensuring a fully debugged compilation environment.

One of the most annoying things about the Flutter ecosystem is the Flutter updates, project packages that can BREAK our project.


Únete a la comunidad de desarrolladores que han decidido dejar de picar código y empezar a construir productos reales. Recibe mis mejores trucos de arquitectura cada semana:

I agree to receive announcements of interest about this Blog.