Building different app flavors with Flutter

For one of the projects we’re working on, we planned to release a mobile app version with OpenStreetMap and the Google Maps version.

How to manage multiple build “flavors” in Flutter?

What is a “build flavor”?

Sometimes you need to build different software versions based on “branding” or “features”. For example, you may enable or disable some software components to produce a “lite” version of the app. Or you might need to compile and link to different libraries depending on the target environment.

The difference between a “build flavor” and a fork is that in a group of “build flavors” there is only one copy of the source code: this means that the two “versions” of the software are strictly coupled, like if they’re one software only. Differently, a fork has a life on its own, which might diverge a lot from the “main” version.

Build flavors in SeismoCloud

In our research project SeismoCloud, we continuously publish our app in the Apple App Store and the Google Play Store. Due to my interest in Google-free Android, I recently pushed to have a “free version”.

Even if the app itself is not FOSS yet (due to some copyright paperwork), we published an F-Droid version built using FOSS libraries (mostly: OpenStreetMap in place of Google Maps). Thanks to this change, Google-free Android smartphones can run SeismoCloud without issues.

Build flavors with Flutter

It’s pretty easy to define a build flavor in Flutter. We do this by defining an environment variable and using this variable to check which kind of flavor is running.

Open the file where you put your global constants, and use something like:

const String flavor = String.fromEnvironment("app.flavor");

Now you can use this constant to select the code you want. In other words, you can do this in the build() function:

Widget _getMap() {
  if (constants.flavor == "foss") {
    return MapFOSSWidget();
  } else {
    return MapWidget();
  }
}

In this way, when the flavor is foss, the MapFOSSWidget will be used (which implements OSM). Otherwise, MapWidget will be used (which implements Google Maps).

In your pubspec.yml you should list all your dependencies for all flavors.

Important note: with this method, your final app will still have all dependencies, probably because the flutter compiler cannot tell the difference on “flavors”. If you want to eliminate those, you’ll need to set up scripts to eliminate dependencies (and all the code that depends on those) from the source before the build. That is something I’ll do in the future.