Flavoring Flutter
If you read my last Flutter story you know that we had a problem configuring flavors in Flutter.If you read my last Flutter story you know that we had a problem configuring flavors in Flutter.
Why to use flavors
Working alone as a hobbyist android developer I never looked at flavors/build-config. I did not need them, I was the only person of my team and the only stakeholder ¯\(ツ)/¯
Here at Iakta the team is bigger and we have many customers, so if something goes wrong you cannot just yell at the mirror.

Flavors are just comfortable. They let you define some build configuration and switch them as you want. For example you could have one flavor for development, and one for production. You can set different url for api calls or different icons and app names. With a click you’re ready to develop or to release your great application.
We use a lot flavor configurations, not only for comfort, but also to be sure to deploy the right version of the app. We just set different icons and sometimes even app theme to be sure not to release an app with an api url pointing to local or staging machines. That would be very dangerous and shameful.

Usually we use from 3 to 5 different flavor per app (development, production, staging, demo..)
Flavors in Flutter
When it comes to Flutter, flavors are easy to implement, but if you don’t know android flavors and iOS schema you can have some problem. I used to use android buildConfigs and iOS targets and so it was not so straightforward.
Flutter cli has an option for flavors, so you can run/build your app using flavors:
flutter build --flavor development
These are mapped to android productFlavors and iOS schema.
Android productFlavors
Regarding android the productFlavors are defined in the app gradle module.

As you can see is pretty straighforward and you can set different application id suffix.
Note that flavor names have to be the same as the cli flutter command.
Now for example you can add icons based on flavor type.



iOS schema
In iOS is a bit trickier.
After some time I think this is the easiest way to do this.
Create in the ios/Flutter folder a configuration file for every flavor, including the Generated.xcconfig file and setting FLUTTER_TARGET to the main file required by the target.

//
// development.xcconfig
// Runner
//
// Created by Salvatore on 26/04/18.
// Copyright © 2018 The Chromium Authors. All rights reserved.
//
#include "Generated.xcconfig"
FLUTTER_TARGET=lib/main-dev.dart
server_url = www.iatka.it/api/dev
server_port = 8080
protocol = http
Here you can also define some environment variables you can need in you platform-side code. For example some url.
Then create a new scheme for every flavor.

Remember to check the shared checkbox in the dialog.

Now select the Runner project and add the configurations you need selecting as configuration file the one created before.

Note that you need to have two configurations for each flavor named with Release-[flavorName] and Debug-[flavorName]. Names are really important for flutter matching reasons.
A flavor plist file is also required to set things like bundleId or the variables defined in the xcconfig file.

To link the plist files to the configurations go to the Runner target

Regarding the icons they can be set in the Runner target in the Asset Catalog App Icon Set Name option.

Done!
Flavors in dart code
How to use flavors in dart code? There is no way to get the flavor in flutter code.
We found that the only way to solve this problem is to use Flutter targets.
When running your app you are able to choose the main file using the cli option -t (or —target):
flutter build --flavor development -t lib/main-dev.dart
In this way the entry point of the app is set to main-dev.dart.
How to exploit this command? The easiest thing is to create a config.dart file with a Config class and a Flavor enum.
enum Flavor {
DEVELOPMENT,
RELEASE,
}
class Config {
static Flavor appFlavor;
}
Using the appFlavor static field we’re able to set different flavors in different main files.
main-dev.dart
import 'package:flutter/material.dart';
import 'package:flutter_flavors/appEntry.dart';
import 'package:flutter_flavors/config.dart';
void main() {
Config.appFlavor = Flavor.DEVELOPMENT;
runApp(new MyApp());
}
In this way it’s easy to know if we’re in the dev or production version.
import 'package:flutter/material.dart';
enum Flavor {
DEVELOPMENT,
RELEASE,
}
class Config {
static Flavor appFlavor;
static String get helloMessage {
switch (appFlavor) {
case Flavor.RELEASE:
return 'RELEASE';
case Flavor.DEVELOPMENT:
default:
return 'DEVELOPMENT';
}
}
static Icon get helloIcon {
switch (appFlavor) {
case Flavor.RELEASE:
return new Icon(Icons.new_releases);
case Flavor.DEVELOPMENT:
default:
return new Icon(Icons.developer_mode);
}
}
}
For example here we can show different messages and icons based on flavor type. As easy as this!

So this would be our final configuration: two main files and a configuration file.



Final considerations
Yes, I know. It’s a mess, but it’s a “una tantum” thing that can save you time and life.
You can find the example repository at https://github.com/iakta/flutter_flavors.
If I made something wrong or I missed something just write me. Comments and considerations are more than welcome!