Flutter is experiencing rapid growth, leading to a wide range of use cases. As a consequence, there is a possibility of introducing breaking changes. Deploying such changes directly to app stores without thorough testing can be risky. Additionally, running regression tests is essential to ensure that existing features remain intact. To mitigate these risks, the concept of "flavors" comes into play.
Flavors offer a solution by allowing developers to create different variations or environments of the same app. This enables efficient management of various configurations, such as development, staging, and production environments, without affecting the core functionality of the app.
Android:
create folders matching the names of the flavor inside your android/app/src/
something like this.
Inside your
android/app/src/build.gradle
just afterdefaultConfig
you should have this:flavorDimensions "app" productFlavors { dev { dimension "app" versionNameSuffix "optional string" applicationId "com.example.app.dev" versionCode flutterVersionCode.toInteger() versionName flutterVersionName } beta { dimension "app" versionCode flutterVersionCode.toInteger() versionName flutterVersionName } prod { dimension "app" versionNameSuffix "optional" applicationId "com.example.app" versionCode flutterVersionCode.toInteger() versionName flutterVersionName } }
flavorDimensions: In the context of Flutter app development,
flavorDimensions
is analogous to the global key used to control which flavor of the app will be built. It acts as a grouping mechanism that allows developers to categorize and differentiate various flavors based on specific characteristics or configurations.productFlavors: This section contains a list of all the different flavors that you wish to define for your Flutter app, along with their respective configurations. By utilizing
productFlavors
, you can set up multiple variations of your app to cater to different environments, such as development, staging, and production. In the example provided, the app has three flavors defined.dimension: The dimension attribute is used to establish a connection with the
flavorDimensions
that you have defined earlier. It links each flavor to its correspondingflavorDimension
. In this example, the dimension is called "app."versionNameSuffix (Optional):
versionNameSuffix
is an optional attribute that allows you to add custom text to the version name or build number of your app. It can be useful for distinguishing different builds based on the flavor. For instance, you can add ".dev" to the version name of the dev flavor to indicate its development nature.applicationId (Optional): The applicationId is a unique identifier for every Android app. By specifying applicationId in each flavor configuration, you can control the package name for each flavor independently. This enables you to test the app as separate applications without affecting your existing production builds. In the example provided, ".dev" is added to the applicationId of the dev flavor.
versionCode (Optional): versionCode represents the build number of the app. It is an essential attribute for differentiating between various app versions. In this example, the build number is sourced from the pubspec.yaml file.
versionName (Optional): versionName indicates the version number of the app. Similar to VersionCode, it helps users identify the app's different releases. In the example provided, the version name is also derived from the build number in the pubspec.yaml file.
By leveraging these configurations, developers can easily manage and build different flavors of their Flutter app while seamlessly integrating Firebase services to cater to specific use cases and environments.
iOS:
1. Click on Runner then select Runner under Project then add your expected flavors with their corresponding Debug, Profile and Release Configurations
before:
then:
2. Click on the runner on the top part of code and create schemes for the flavors, in our case we'll create for dev, prod and beta.
before:
Then:
3. Match the Schemes to their corresponding Runners
NB: This has to be done for all the created schemes.
4. Matching the main.dart file to their corresponding scheme (note that this is not necessary if you have only one main.dart file).
Click on Runners under Targets and click on Build settings, scroll down to FLUTTER_TARTGET then define the path for each scheme.
The default is lib/main.dart
Run your app on both Android and iOS with the specific flavours to be sure everything works as expected before we begin the Firebase integrations.
To Run:
prodflutter run --flavor prod
devflutter run --flavor dev
betaflutter run --flavor beta
FIREBASE SETUP
Our goal for this session is to use different Firebase DB for each of our flavors.
Android:
Drop the corresponding google-services.json
file in the corresponding flavor folder.
NB: The google-services.json
files are unique to the DB we intend to use for each flavor.
That's that for Android.
iOS:
This one is quite tricky so you need to pay attention to details.
Firstly, you need to create a folder and add the corresponding Google services plist files with a distinctive name.
Then click on Runners under Targets and click on Build phases create a new phase, we'll name ours Copy Google Plist file
. and move it right under "Run script"
# Type a script or drag a script file from your workspace to insert its path.
PATH_TO_GOOGLE_PLISTS="${PROJECT_DIR}/Config"
echo "build config is ${CONFIGURATION}"
case "${CONFIGURATION}" in
"Dev-Debug" | "AdHoc_Staging" | "Dev-Release" | "Debug")
cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info-dev.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;;
"Beta-Debug" | "AdHoc_Staging" | "Beta-Release" | "Debug")
cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info-beta.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;;
"Prod-Debug" | "Profile" |"Prod-Release" |"Release")
cp -r "$PATH_TO_GOOGLE_PLISTS/GoogleService-Info-prod.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist" ;;
*)
;;
esac
This build phase code is a script written in shell (bash) that is executed during the build process of an Xcode project. It copies different configurations of a GoogleService-Info.plist file to the built products directory based on the build configuration selected in Xcode.
Here's a breakdown of what the script does:
The variable
PATH_TO_GOOGLE_PLISTS
is set to the path of the folder where the different configurations of GoogleService-Info.plist files are stored. This folder is assumed to be located in the "Config" directory within the project directory.The script echoes the current build configuration (e.g., "Dev-Debug", "Beta-Release", "Prod-Release", etc.) to the console.
The script uses a
case
statement to check the value of theCONFIGURATION
variable (the current build configuration) and performs different actions based on the configuration.For each specific build configuration, the script copies the corresponding GoogleService-Info.plist file to the built products directory (the folder where the final app is built).
If the configuration is one of "Dev-Debug", "AdHoc_Staging", "Dev-Release", or "Debug", it copies the GoogleService-Info-dev.plist to the built products directory with the name "GoogleService-Info.plist."
If the configuration is one of "Beta-Debug", "AdHoc_Staging", "Beta-Release", or "Debug", it copies the GoogleService-Info-beta.plist to the built products directory with the name "GoogleService-Info.plist."
If the configuration is one of "Prod-Debug", "Profile", "Prod-Release", or "Release", it copies the GoogleService-Info-prod.plist to the built products directory with the name "GoogleService-Info.plist."
If the configuration does not match any of the specified cases, it does nothing (empty
*)
case), and the build proceeds without any specific copying action.
This script allows the Xcode project to have different configurations for GoogleService-Info.plist based on the selected build configuration, making it easier to handle different environments or settings (e.g., development, staging, production) for the Google services used in the app.
After all of these setups, initialize Firebase, run your application and be sure it runs without any errors.
Happy Coding!!! ๐๐๐