Creating flavors of a Flutter app (Flutter & Android setup)

It’s quite common for a native Android app to use productFlavors to set up several apps from the same source code. So, how easy is this to implement in Flutter?

In this code tutorial, we will set up a project with 2 app flavors. Each app will display the app name (specific per flavor), the current date (shared functionality, which includes a string), a short description (specific per flavor), and two images (one specific per flavor, one shared).

Note: The code tutorial only involves the Flutter and  Android set up, not the iOS set up, because I am not proficient in building and publishing iOS apps.


Code tutorial index

Setting up the app as a single app
Adding flavors (Android setup)
Adding flavors (Flutter setup)
Customising some string resources based on flavor
Customising some assets based on flavor

Setting up the app as a single app

To follow the code tutorial, create a new app as follows.

If you’re unsure how to set up a Flutter app, check out Getting started with Flutter official tutorial.

Firstly, we create a Material app in main.dart, which will launch the HomePage widget.

 

Secondly, we create home_page.dart. It displays the app name, the current date, a short description, and two images.

 

Thirdly, we create a resource folder, and a new file display_strings.dart in in.

 

Fourthly, we add the intl package (used for date formatting) to pubspec.yaml as below, then do flutter packages get .

 

Lastly, we set up the images. Create a folder assets (on same level as lib), then add images dancing.png and 1.png (right click on files then save), and amend the pubspec.yaml as below.

Back to code tutorial index

Adding flavors (Android setup)

Now, we will create 2 flavors of our app, called app1 and app2. To do this, we amend android/app/build.gradle file as below.

 

We also amend the AndroidManifest.xml (in android/app/src/main folder) to use an app name specified in an Android string resource.

 

Then, we provide the app name string for each app. In android/app/src/main/res/values, we create strings.xml as below.

 

Finally, we create folders app1 and app2 under android/app/src. In each new folder, we create a folder res then a folder values. Inside each new values folder, we create strings.xml as below.

 

Flutter run and build commands come with a –flavor flag. So, from the command line, you can simply type flutter run --flavor app1  and flutter fun --flavor app2 .

Gotcha 1: As of writing and on my system, you need to do flutter clean  in between running different flavors.

Gotcha 2: –flavor flag currently fails if the Android flavor name has an uppercase character in it, so make sure your Android flavor names are all lowercase! 

If you prefer using an IDE, you can edit your configurations and pass in the flavor in it. So let’s create 2 configurations in the IDE, as per screenshots below.

Select Edit Configurations
Select Edit Configurations
Rename to App1
Rename to App1
Add build flavor
Add build flavor
Select Add new configuration
Select Add new configuration
Select Flutter
Select Flutter
Name App2
Name App2
Add Dart entrypoint
Add Dart entrypoint
Add build flavor
Add build flavor
Select Share
Select Share

 

At this point, when you run each app, you will see the same thing on screen. However, you should see the correct app name when you view the list of apps on your device (ie “App 1” and “App 2”).

 

 

Back to code tutorial index

Adding flavors (Flutter setup)

Following the advice from Separating build environments in Flutter apps, part #1 – environment-specific configuration in Dart side, we will create an app_config.dart file, which is an Inherited Widget. Such a Widget allows for the app config data to be accessed from any widgets in the app.

 

Then, we rename main.dart to main_common.dart, amend it slightly, and create main_app1.dart and main_app2.dart files.

 

Then, we edit home_page.dart to show the app name. We also remove APP_TITLE string from display_strings.dart.

 

Finally, to launch each config from the command line, you can simply type flutter run --flavor app1 -t lib/main_app1.dart  and flutter run --flavor app2 -t lib/main_app2.dart

Or, from the IDE, you can edit each configuration as per screenshots below.

Amend Dart entrypoint for App2
Amend Dart entrypoint for App2
Amend Dart entrypoint for App1
Amend Dart entrypoint for App1

 

Note: renaming main.dart to main_common.dart means that we have to pass in a main file name when launching the app (as the default doesn’t exist), so we never accidentally launch the non configured app.

Gotcha 3: when launching from the IDE, I sometimes need to relaunch because even though I am launching “App2”, “App1” is being launched. But a hot restart usually fixes this. On a few rare occasions, I need to do  flutter clean .

At this point, when you run each app, you will see the correct app title, but all the other strings and images are the same.

 

Back to code tutorial index

Customising some string resources based on flavor

In Android, we are used to overloading the xml resources so we can specify a different one for a different flavor. By this, I mean what we did above for the Android app_title string resource – we keep the name, we just give it a different value.

As everything in Flutter is Dart code, we need to use a Dart construct, that is an abstract class.

Let’s look at how it works in practice, by making the string APP_DESCRIPTION customizable per flavor.

We amend app_config.dart to add the abstract string class.

 

We remove APP_DESCRIPTION string from display_strings.dart and create 2 new files, in /lib/resource, named display_strings_app1.dart and display_strings_app2.dart, as below.

 

Note: by using an abstract class, we cannot forget to implement a string for a given flavor.

Then, we need to amend main_app1.dart and main_app2.dart to specify which string resource to use.

 

And we need to amend home_page.dart so it uses the string from the StringResource.

Back to code tutorial index

Customising some assets based on flavor

As assets are specified in a folder, we can use a file structure to specify which asset to use, and then we can use the appInternalId (specified in AppConfig) to retrieve the correct one.

Firstly, we create folders 1 and 2 under assets. We  then rename 1.png to icon.png and move it to the 1 folder. We then download and save 2.png in the 2 folder, and rename it to icon.png.

Secondly, we amend the home_page.dart to specify the correct icon based on the appInternalId.

 

Finally, we amend pubspec.yaml.

Back to code tutorial index

Voila!

App 1
App 1
App 2
App 2

 

What next?

So, you’ve learned a way to use flavors in Flutter. There are a few different ways, so for a full understanding of your options, I recommend you checkout Flavoring Flutter

Author: Natalie Masse Hooper

Mobile app developer with 14 years experience. Started with the Android SDK in 2010 and switched to Flutter in 2017. Past apps range from start ups to large tech (Google) and non tech (British Airways) companies, in various sectors (transport, commercial operations, e-commerce).

11 thoughts on “Creating flavors of a Flutter app (Flutter & Android setup)”

  1. Dear Sir

    about productFlavors i have a problem

    as native —different flavor can use diff AndroidManifest

    like :

    sourceSets{
    main {
    manifest.srcFile ‘src/main/AndroidManifest.xml’

    }
    flutter {
    manifest.srcFile ‘src/flutter/AndroidManifest.xml’

    }

    native_app {
    manifest.srcFile ‘src/native_app /AndroidManifest.xml’

    }
    }

    but Flutter project main AndroidManifest has { application
    android:name=”io.flutter.app.FlutterApplication”}

    this FlutterApplication is for Flutter

    not at native_app !!

    so native_app AndroidManifest need replace io.flutter.app.FlutterApplication

    so will merge AndroidManifest ( main+flutter / main+ native_app)

    but the AS will show error — AndroidManifest merge fail !! (two Application ??… )

    so try remove io.flutter.app.FlutterApplication

    native flavor use native build is pass

    but

    flutter build show error — {No application found for TargetPlatform.android_arm64. Is your project missing an android\app\src\main\AndroidManifest.xml?}

    how to fix ?

    THX

  2. Hello! Thanks for sharing this tutorial :·)

    One question, just to clarify: both flavors are going to have both png files, aren’t they? Or is there any kind of minification or shrinking done by flutter automagically when building the release APK, so the unused png is deleted on building time?

    Thanks a lot!

  3. Hello.
    Thanks for this tutorial.

    Can I use this solution for 2 completely different bundle ids? Like com.example.app1 and com.example.app2.
    I have one source code for 2 apps with different colors and layouts. This apps are already in stores and I need to use their bundle ids.

    I have problem with build. I am not sure, how to configure AndroidManifest.xml in main folder. How should looks like this row: ?

    Thanks for you response.

  4. Will adding both “assets/1” and “assets/2” increase apk size? Because for flavour 1 I just need “assets/1”.

    1. Yes, it will increase app size. You will get app with Flutter assets from all variants included. That sucks and in some scenarios it’s unacceptable.

  5. That’s useless, because each apk will contain unnecesary assets from all flavors. Let’s imagine I have 10 flavors and 10 MB of assets for each flavor. Final apk will get 90 MB unnecesary assets.

    1. I suggest you create a script in your CI pipeline, as follows:

      Assuming you have a structure such as assets/common for common files, and assets/A, assets/B and so on, for flavours A, B etc. Then, to build flavour A, you would do the following:
      – checkout out your repo
      – remove all files under assets, except those in assets/A and assets/common
      – flutter build

      Or your CI script can amend the pubspec to remove assets/B etc from it. Whichever way you do it, using CI to build all your flavours, it’s quite doable.

      That way, your apk will not have unnecessary asset files. While it is an extra CI step, it’s just a one off setup for your CI script so not a lot of work. I would expect you have CI for an app with flavors: if not, you really should, as your release process must be very tedious without it!

  6. Nice information provided on flavor also will there be any update on web, windows, mac & linux versions of code may be currently it might be too early but in coming days

Leave a Reply

Your email address will not be published.