Welcome Flutter developers! In this technical, yet reader-friendly blog post, we will be discovering the benefits and intricacies of using Flutter flavors for creating separate environments within the same code base for an app. This guide will accurately detail the process of defining build configurations, implementing necessary files, and launching app flavors for both Android and iOS. Let's start our journey!
As development processes become more elaborate and scalable, managing different environments like debug, beta, or production for the same Flutter app can become quite a task. This is where the beauty of Flutter flavors sparkles. Known as build configurations in iOS, Flutter flavors allow developers to create separate environments for their apps using the same code base.
How does this become helpful for the application development process? Suppose we need to create separate apps - one for testing experimental features (the dev flavor), and another for delivering the full-fledged production app (the prod flavor). Flutter flavors come as a rescue, set up both app versions without writing two separate apps.
Flutter flavors also let us define compile-time configurations and set parameters that are read at runtime. This feature helps customize the behavior of our app to suit the needs of specific versions or environments. The usage doesn't end here; you can even use Flutter flavors to develop different versions of your app like a free version with specific features and ads, and a paid version with additional features and no ads. All of which use the same code base!
Let's dive deeper into the prerequisites and steps required to set up and use these flavors in our Flutter project.
The preparation phase before setting up Flutter flavors involves ensuring that a few prerequisites are in place. These primarily include having Xcode installed on your machine and an existing Flutter project where you are planning to add flavors. Once these are ensured, we can move forward to the actual process of creating and using Flutter flavors in iOS and Android environments.
Under iOS, the build configurations (or flavors) are created and managed using Xcode. The steps involved in this process might seem tedious but bear in mind the flexibility and control you gain over different versions of your app.
1. Begin by opening your Flutter project in Xcode. Here you will find the option to define new schemes and build configurations. Navigate to Product > Scheme > New Scheme from the menu to add a new scheme. A scheme, in the Xcode context, describes how Xcode carries out different actions to the build process.
1 // Example code snippet 2 void main() { 3 runApp(MyApp()); 4 } 5 6 class MyApp extends StatelessWidget { 7 // This widget is the root of your application. 8 9 Widget build(BuildContext context) { 10 return MaterialApp( 11 title: 'Flutter Demo', 12 theme: ThemeData( 13 // This is the theme of your application. 14 // 15 // Try running your application with "flutter run". You'll see the 16 // application has a blue toolbar. Then, without quitting the app, try 17 // changing the primarySwatch below to Colors.green and then invoke 18 // "hot reload" (press "r" in the console where you ran "flutter run", 19 // or simply save your changes to "hot reload" in a Flutter IDE). 20 // Notice that the counter didn't reset back to zero; the application 21 // is not restarted. 22 primarySwatch: Colors.blue, 23 ), 24 home: MyHomePage(title: 'Flutter Demo Home Page'), 25 ); 26 } 27 } 28
In this guide, we'll use "debug_dev" as an example for our dev scheme.
2. The next step is to duplicate the build configurations to differentiate between the default configurations that are already available and the new configurations for the dev scheme. You can do this by clicking on the plus button at the end of the Configurations dropdown list under the Info tab, and duplicate each configuration name (Debug, Release, and Profile).
3. To match your dev scheme, add -dev at the end of each new configuration name.
4. The newly created dev scheme can now be changed to match the build configurations already created. This can be done by navigating to your Runner project and clicking on Manage Schemes.
5. A pop-up window will open. Double click on the dev scheme. You'll modify each scheme to match its dev build configuration shortly.
That's it! You've successfully created your dev scheme!
Now that we have set up our dev scheme, the next step is to customize it, for example, by adding a different bundle identifier for each flavor.
1. A bundle identifier uniquely identifies your application. In our case, we'll set the Debug-dev value to equal com.flavor-test.dev. You can change the app bundle identifier to differentiate between schemes. For example, append .dev to the -dev scheme value in Product Bundle Identifier.
2. Afterwards, head to the Build Settings in Xcode Project. Set the Product Name value to match each flavor. For the dev flavor, you could set it as Debug Dev.
3. Additionally, you need to add the display name to Info.plist. It can be done by updating the Bundle Display Name value to $(PRODUCT_NAME).
With these steps, you've set up and customized your dev scheme in Xcode, and established the build configurations for it. Congrats on this important milestone!
If your Flutter app utilizes a Flutter plugin, it's vital to update the ios/Podfile. In this file, change the default for Debug, Profile, and Release to match the Xcode build configurations for the dev scheme.
The updated ios/Podfile would look similar to the following:
1 project 'Runner', { 2 'Debug-dev' => :debug, 3 'Profile-dev' => :release, 4 'Release-dev' => :release, 5 } 6
Now your iOS app is fully equipped to represent different flavors, thanks to build configurations!
Adding flavors to your Android app can help you manage multiple versions or configurations of your app, from the same code base, each tailored for different use cases or environments!
Setting up flavors in Android involves adjusting parameters in the build.gradle file residing inside your project's android/app directory.
1. Create a flavorDimension to group your added product flavors. Gradle doesn’t combine product flavors that share the same dimension.
1 flavorDimensions "default" 2
2. Following this, add a productFlavors object with the desired flavors along with values for dimension, resValue, and 'applicationIdSuffix' or 'applicationId'.
1 productFlavors { 2 dev { 3 dimension "default" 4 resValue "string", "app_name", "dev flavor example" 5 applicationIdSuffix ".dev" 6 } 7 } 8
In the productFlavors object,
Now, your Android app is ready to handle different flavors.
To conveniently work with your flavors in running and debugging modes, you will need unique launch configurations. A launch.json file allows you to run the command flutter run --flavor [flavor name].
1. In the root directory of your flutter project, add a folder called .vscode.
2. Inside the .vscode folder, create a file named launch.json.
1 { 2 // The root directory for your Flutter project 3 "root": "C:/path/to/my/flutter/project", 4 ".vscode": { 5 // The launch.json file can be created here 6 } 7 } 8
3. In the launch.json file, add a configuration object for each flavor. Each configuration consists of a name, request, type, program, and args key. The args key should contain ["--flavor", "[flavor name]", "--target", "lib/main_[flavor name].dart" ].
1 { 2 "version": "0.2.0", 3 "configurations": [ 4 { 5 "name": "dev", 6 "request": "launch", 7 "type": "dart", 8 "program": "lib/main_dev.dart", 9 "args": ["--flavor", "dev", "--target", "lib/main_dev.dart" ] 10 } 11 ], 12 "compounds": [] 13 } 14
With this setup, you can now run the terminal command flutter run --flavor dev or you can set up a run configuration in your IDE.
This is how you can adequately manage your launch configurations.
Once the flavors are set up, it's time to modify your app's Dart code to accommodate and consume these flavors. This gets done in the lib / main.dart file.
Let's take a look at how to do this:
1 void main() { 2 // Choose the correct main_*.dart file per the flavor 3 const String flavor = String.fromEnvironment('FLAVOR'); 4 5 if (flavor == 'dev') { 6 runApp( 7 DevicePreview( 8 builder: (context) => const MyApp(), 9 ), 10 ); 11 } else { 12 runApp(const MyApp()); 13 } 14 } 15 16 class MyApp extends StatelessWidget { 17 const MyApp({Key? key}) : super(key: key); 18 19 20 Widget build(BuildContext context) { 21 return MaterialApp( 22 title: 'My Flutter app', 23 theme: ThemeData(scaffoldBackgroundColor: Colors.white), 24 home: HomeScreen(), 25 ); 26 } 27 } 28
In the code above, I've created a Flutter function component MyApp that builds a MaterialApp. The void main() function checks the flavor set in the environment and decides which main_*.dart file to runApp with.
You can then test the setup using the flutter run --flavor dev command at the command line, or in your IDE.
Flavors in Flutter are a powerful tool to add to your app development arsenal. Mastering them can result in efficient and scalable codebases for various app versions or environments.
To further deepen your understanding and practical knowledge of Flutter flavors, a variety of resources are available online, including comprehensive guides, example projects, and interactive tutorials. Exploring these resources will allow you to see walkthroughs of build flavors for both Android and iOS, learn about different strategies to deal with various scenarios, and even discover how to integrate Flutter flavors with Firebase or other services.
There are several excellent packages that not only simplify the creation of Flutter flavors but also offer additional functionality. Some noteworthy packages to consider are:
flutter_flavor: This package provides a set of widgets and helpers to easily support multiple flavors in a Flutter application.
flutter_flavorizr: As the name suggests, this package aims to simplify the entire flavor creation process for Flutter projects. With flutter_flavorizr, you can easily handle the build settings, app name, bundle identifier, and many more aspects of your Flutter flavors.
Flutter flavors offer you great flexibility when dealing with different app versions, environments, or features.
Harnessing the power of Flutter flavors can revolutionize the development process of your app. This feature allows you to manage different environments and versions efficiently, using a common code base. Be it controlling build settings, handling API URLs, or developing tailored versions of an iOS or Android app, Flutter flavors can effectively streamline these tasks.
This blog has walked you through the intricate details of setting up and using flavors for your iOS and Android Flutter apps, from the primary steps of environment setup to launching your app flavors. To continually improve, remember to explore more resources and experiment with the numerous packages available.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.