Question #78EasyFlutter Basics

What is flavours in flutter ?

#flutter

Answer

What are Flavors in Flutter?

Flavors (also called build variants or product flavors) are different versions of your Flutter application that share the same codebase but have different configurations, features, or branding. They allow you to build multiple variants of your app from a single codebase, such as development, staging, and production versions.

Common Use Cases for Flavors

Flavor TypeUse CaseExample
Environment-basedDifferent API endpointsdev, staging, production
Feature-basedDifferent feature setsfree, premium, enterprise
Brand-basedWhite-label appsClient A, Client B, Client C
Platform-basedRegion-specific versionsUS, EU, Asia versions

Setting Up Flavors

1. Android Configuration (android/app/build.gradle)

gradle
android {
    defaultConfig {
        applicationId "com.example.myapp"
        // ... other config
    }

    flavorDimensions "environment"

    productFlavors {
        dev {
            dimension "environment"
            applicationIdSuffix ".dev"
            versionNameSuffix "-dev"
            resValue "string", "app_name", "MyApp Dev"
        }

        staging {
            dimension "environment"
            applicationIdSuffix ".staging"
            versionNameSuffix "-staging"
            resValue "string", "app_name", "MyApp Staging"
        }

        production {
            dimension "environment"
            resValue "string", "app_name", "MyApp"
        }
    }
}

2. iOS Configuration (ios/Runner.xcodeproj)

In Xcode:

  1. Select the project in the navigator
  2. Go to "Info" tab
  3. Duplicate the "Debug" and "Release" configurations
  4. Name them (e.g., Debug-dev, Release-production)

Or modify

text
ios/Flutter/Debug.xcconfig
and
text
ios/Flutter/Release.xcconfig
:

xcconfig
// Debug-dev.xcconfig
#include "Generated.xcconfig"
APP_NAME=MyApp Dev
APP_BUNDLE_ID=com.example.myapp.dev

3. Flutter Flavor Configuration

dart
// lib/main_dev.dart
import 'package:flutter/material.dart';
import 'app.dart';
import 'config/app_config.dart';

void main() {
  AppConfig.setFlavor(Flavor.dev);
  runApp(MyApp());
}

// lib/main_staging.dart
import 'package:flutter/material.dart';
import 'app.dart';
import 'config/app_config.dart';

void main() {
  AppConfig.setFlavor(Flavor.staging);
  runApp(MyApp());
}

// lib/main_production.dart
import 'package:flutter/material.dart';
import 'app.dart';
import 'config/app_config.dart';

void main() {
  AppConfig.setFlavor(Flavor.production);
  runApp(MyApp());
}

Flavor Configuration Class

dart
// lib/config/app_config.dart
enum Flavor {
  dev,
  staging,
  production,
}

class AppConfig {
  static Flavor? _flavor;

  static void setFlavor(Flavor flavor) {
    _flavor = flavor;
  }

  static Flavor get flavor => _flavor ?? Flavor.production;

  static String get appName {
    switch (flavor) {
      case Flavor.dev:
        return 'MyApp Dev';
      case Flavor.staging:
        return 'MyApp Staging';
      case Flavor.production:
        return 'MyApp';
    }
  }

  static String get apiBaseUrl {
    switch (flavor) {
      case Flavor.dev:
        return 'https://dev-api.example.com
      case Flavor.staging:
        return 'https://staging-api.example.com
      case Flavor.production:
        return 'https://api.example.com
    }
  }

  static bool get isProduction => flavor == Flavor.production;
  static bool get isDevelopment => flavor == Flavor.dev;
}

Running Different Flavors

bash
# Run dev flavor
flutter run --flavor dev -t lib/main_dev.dart

# Run staging flavor
flutter run --flavor staging -t lib/main_staging.dart

# Run production flavor
flutter run --flavor production -t lib/main_production.dart

# Build APK for specific flavor
flutter build apk --flavor production -t lib/main_production.dart

# Build iOS for specific flavor
flutter build ios --flavor production -t lib/main_production.dart

VS Code Launch Configuration

Create

text
.vscode/launch.json
:

json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Dev",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_dev.dart",
      "args": ["--flavor", "dev"]
    },
    {
      "name": "Staging",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_staging.dart",
      "args": ["--flavor", "staging"]
    },
    {
      "name": "Production",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_production.dart",
      "args": ["--flavor", "production"]
    }
  ]
}

Best Practices

  1. Use Environment Variables: Store sensitive data in environment variables, not in code
  2. Different App Icons: Use different icons for each flavor to easily identify them
  3. Separate Firebase Projects: Use different Firebase configurations for each flavor
  4. Database Separation: Use different database names/endpoints for each environment
  5. Analytics Tracking: Separate analytics properties for each flavor

Popular Packages for Flavor Management

  • flutter_flavor: Simplifies flavor configuration
  • flutter_config: Manages environment variables
  • flutter_dotenv: Loads configuration from
    text
    .env
    files
yaml
# pubspec.yaml
dependencies:
  flutter_flavor: ^3.1.0
  flutter_dotenv: ^5.1.0

Important: Never commit sensitive API keys or credentials to your repository. Use environment variables or secure secret management for production builds.

Documentation: Flutter Build and Release