Configuring Flavor/Scheme for Mobile App Versions
Picture this: your fintech startup releases a white-label app for three banks. Each has its own design, API endpoint, and bundle. QA needs to test staging without risking production data. Without proper Flavor/Scheme setup, you'll get package name confusion and be unable to install two versions side by side. We solve this in 2–5 days using Product Flavors (Android), Schemes/Targets (iOS), and Flutter configurations. In 5 years we've completed over 30 projects—from fintech to B2B white-label. We guarantee that after setup, you can install all versions on one device simultaneously without conflicts.
How to Set Up Flavors on Different Platforms?
Android: Product Flavors
Product Flavors in Android create separate app variants with different applicationIds, resources, code, and dependencies.
android { flavorDimensions += listOf("environment", "tier") productFlavors { create("dev") { dimension = "environment" applicationIdSuffix = ".dev" versionNameSuffix = "-dev" resValue("string", "app_name", "MyApp Dev") } create("staging") { dimension = "environment" applicationIdSuffix = ".staging" versionNameSuffix = "-staging" resValue("string", "app_name", "MyApp Staging") } create("production") { dimension = "environment" } create("free") { dimension = "tier" applicationIdSuffix = ".free" } create("paid") { dimension = "tier" } } } This creates a matrix: devFreeDebug, devPaidRelease, productionFreeRelease, etc. Usually we use only the needed combinations and explicitly filter the rest via variantFilter. Flavor-specific resources go into src/dev/res/, src/staging/res/, src/production/res/. Kotlin code goes into src/dev/kotlin/ etc.
iOS: Targets and Schemes
On iOS, the role of Flavors is played by the combination of Targets + Schemes + xcconfig. Apple Developer Documentation recommends this approach for separating configurations.
One Target, Multiple Schemes + Build Configurations — for staging/production:
- Create configurations: Debug, Staging, Release
- Create Schemes: MyApp, MyApp-Staging
- Each Scheme launches the appropriate Configuration
Multiple Targets — for white-label or substantially different versions (different code, different capabilities):
- Each Target has its own
PRODUCT_BUNDLE_IDENTIFIER, icon, Info.plist - Common code → Shared framework or shared files added to both Targets
- Heavier to maintain but gives maximum control
Targets: MyApp → com.myapp.ios → AppIcon → Release.xcconfig MyApp-ClientB → com.clientb.myapp → AppIconClientB → ClientB.xcconfig MyApp-Staging → com.myapp.ios.staging → AppIconStaging → Staging.xcconfig Flutter: Flavors
Flutter supports flavors natively, mapping to Android Product Flavors and iOS Schemes under the hood:
flutter run --flavor staging -t lib/main_staging.dart flutter build apk --flavor production -t lib/main_production.dart main_staging.dart initializes the app with staging config, main_production.dart with production config. The config is passed via --dart-define or via a separate app_config.dart per flavor. In pubspec.yaml, you can use flutter_flavorizr to generate boilerplate—creating required Targets/Schemes on iOS and Product Flavors on Android from one config file.
What to Choose: One Target or Multiple?
The answer depends on the volume of differences. If it's only bundle ID, API endpoint, and icon—one Target with multiple Schemes is enough. If different code, push capabilities (APNs/FCM), or third-party SDKs are needed—go with multiple Targets (iOS) / flavorDimensions (Android). On Android, flavorDimensions easily combine free vs paid and staging vs production simultaneously. According to our measurements, one Target with multiple Schemes is 3 times faster to configure than multiple Targets.
Why Separating Configurations Saves Time and Headaches?
Imagine QA testing a staging build accidentally deletes the production database? With different bundle IDs this is impossible—the system treats them as separate apps. Dev sits next to production, and you can instantly compare behavior. Also, the App Store Review Guidelines (Section 4.2) require that test versions not be mixed with production ones—we take this into account.
Example from practice: white-label for a coffee chain
We configured 4 brands with different icons, colors, and Geopush API key. Used 2 flavorDimensions (brand, environment) on Android and 4 Targets on iOS. The CI built the release in 3 days. Time savings on each update: 40%.Typical Mistakes When Configuring Flavors
| Mistake | Consequence | Solution |
|---|---|---|
| New flavor without updating CI | Build won't appear in pipeline | Add lane in Fastlane |
| Duplicating code | Reduced maintainability | Use src/ |
| Different versionCode across same flavors | Version confusion | Centralize version management |
Work Process
- Requirements audit (how many variants, what differences, who will build)
- Choose approach: Flavors vs Targets vs combined
- Create resource and code structure (resource overlays, config files)
- Set up CI (Fastlane + GitHub Actions / GitLab CI) for building all variants
- Test side-by-side installation (verify no package name overlap)
- Document the process for adding a new version
Platform Comparison
| Criteria | Android (Product Flavors) | iOS (Targets + Schemes) |
|---|---|---|
| Setup complexity | Low (via Gradle) | Medium (via Xcode Project) |
| Multiple version support | Excellent (flavorDimensions) | Good (Targets require synchronization) |
| White-label (different brands) | Easy (different resources in folders) | Heavier (needs Shared framework) |
| CI/CD integration | Simple (Gradle task) | Medium (Fastlane + xcodebuild) |
| App Store review | Not needed | Separate attention for each Target |
Timeline and Cost
Timeline: 2–3 days for a standard scheme (staging/production), up to 5 days for white-label with multiple brands. Cost is calculated individually after an audit. Get a consultation—contact us, we'll evaluate your project and propose the optimal solution.
Order turnkey flavor setup—your project will be ready for scaling without architectural conflicts.







