In Flutter development, managing different versions or configurations of your app can become complex, especially when dealing with varying APIs, branding, or features for different environments (like development, staging, and production). Build flavors are a powerful way to handle these scenarios. This blog post will guide you through utilizing build flavors in Flutter to manage different configurations of your app efficiently.
What are Build Flavors?
Build flavors allow you to create different versions of your Flutter app from the same codebase. Each flavor can have its own set of configurations, such as different app icons, names, API endpoints, and features. This is especially useful when you need to manage multiple environments (e.g., development, staging, production) or offer different versions of your app with distinct branding.
Why Use Build Flavors?
- Configuration Management: Easily manage different configurations for different environments.
- Code Reusability: Maintain a single codebase while creating multiple versions.
- Branding: Customize app branding (e.g., app icons, names) for each version.
- Feature Toggles: Enable or disable specific features based on the build flavor.
How to Implement Build Flavors in Flutter
Here’s a step-by-step guide on implementing build flavors in your Flutter project:
Step 1: Configure Build Flavors in android/app/build.gradle
Open the android/app/build.gradle
file and add the flavorDimensions
and productFlavors
blocks inside the android
block.
android {
...
flavorDimensions "environment"
productFlavors {
dev {
dimension "environment"
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
resValue "string", "app_name", "My App Dev"
buildConfigField "String", "API_URL", ""https://dev.example.com/api/""
}
staging {
dimension "environment"
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
resValue "string", "app_name", "My App Staging"
buildConfigField "String", "API_URL", ""https://staging.example.com/api/""
}
prod {
dimension "environment"
applicationIdSuffix ".prod"
resValue "string", "app_name", "My App"
buildConfigField "String", "API_URL", ""https://example.com/api/""
}
}
...
}
In this example:
flavorDimensions "environment"
defines a flavor dimension named “environment.”dev
,staging
, andprod
are the product flavors representing the development, staging, and production environments.applicationIdSuffix
appends a suffix to the application ID.versionNameSuffix
adds a suffix to the version name.resValue
sets a string resource value (app name).buildConfigField
defines a build configuration field (API URL).
Step 2: Access Build Configuration Fields in Dart Code
To access the build configuration fields in your Dart code, you need to add the flutter_config
dependency to your pubspec.yaml
file.
dependencies:
flutter:
sdk: flutter
flutter_config: ^2.0.0
Then, initialize FlutterConfig
in your main.dart
file.
import 'package:flutter/material.dart';
import 'package:flutter_config/flutter_config.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FlutterConfig.loadEnvVariables();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: FlutterConfig.get('APP_NAME'),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(FlutterConfig.get('APP_NAME')),
),
body: Center(
child: Text('API URL: ${FlutterConfig.get('API_URL')}'),
),
);
}
}
Step 3: Configure iOS Flavors
For iOS, you need to configure schemes and build configurations in Xcode. Open ios/Runner.xcworkspace
with Xcode.
Step 3.1: Add Build Configurations
- Go to Project > Runner > Info > Configurations.
- Duplicate the
Debug
andRelease
configurations for each flavor (e.g.,Debug-dev
,Release-dev
,Debug-staging
,Release-staging
, etc.).
Step 3.2: Add Schemes
- Go to Product > Scheme > New Scheme.
- Name the scheme after your flavor (e.g.,
dev
,staging
). - Edit the scheme and configure the Build, Run, Test, and Profile actions to use the appropriate build configurations (e.g.,
Debug-dev
,Release-dev
).
Step 3.3: Define Preprocessor Definitions
In the Build Settings for each configuration, define preprocessor definitions:
DEV=1
STAGING=1
PROD=1
Step 3.4: Add User-Defined Settings
Also in Build Settings, add user-defined settings:
APP_NAME = My App Dev
API_URL = https://dev.example.com/api/
Step 4: Access Flavors in iOS Dart Code
To access environment variables in Dart code for iOS, use the dart-define
flag. This requires configuring build scripts to inject these variables at compile time.
Install CocoaPods dependencies with flutter pub get
then configure Build Phases.
- Go to Target > Runner > Build Phases.
- Click + > New Run Script Phase
Run script with configuration to insert the API_URL variable. This solution does not need a plugin dependency because API_URL variable is included when the Flutter build occurs.
echo "API_URL: $API_URL"
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $APP_NAME" "${INFOPLIST_FILE}"
echo "Running flutter build..."
flutter build ios --release
--build-name=1.0.0
--build-number=1
--dart-define=API_URL=$API_URL
Now get env variables via the code:
String apiUrl = const String.fromEnvironment('API_URL', defaultValue: 'https://example.com');
Text('API URL: $apiUrl'),
Step 5: Run Your App with Different Flavors
To run your Flutter app with a specific flavor, use the following commands:
For Android:
flutter run --flavor dev --target lib/main_dev.dart
flutter run --flavor staging --target lib/main_staging.dart
flutter run --flavor prod --target lib/main_prod.dart
For iOS:
flutter run --flavor dev --target lib/main_dev.dart --scheme dev
flutter run --flavor staging --target lib/main_staging.dart --scheme staging
flutter run --flavor prod --target lib/main_prod.dart --scheme prod
Advanced Usage and Tips
- Separate Main Files: Use separate
main.dart
files (e.g.,main_dev.dart
,main_staging.dart
) to initialize flavor-specific configurations. - Conditional Logic: Use conditional logic in your Dart code based on the build flavor.
- Environment Variables: Utilize environment variables for sensitive information like API keys.
Conclusion
Build flavors are an essential tool for managing different configurations of your Flutter app efficiently. By configuring build flavors for Android and iOS, you can maintain a single codebase while creating multiple versions with distinct configurations, branding, and features. This approach simplifies development, testing, and deployment, making your Flutter projects more manageable and scalable.