How to Build Different Versions of Flutter App For QADevProd

How to Build Different Versions of Flutter App For QA/Dev/Prod?

Earlier we have been through the various articles on flutter. So, in this article, we will go through how to build different versions of the flutter app for QA/Dev/Prod.

How to Build Different Versions of Flutter App For QA/Dev/Prod?

Firstly, we need to set up a global representing the BuildEnvironment named env.

env.dart will have a code snippet like the below:

import 'package:meta/meta.dart';

enum BuildFlavor { production, development, staging }

BuildEnvironment get env => _env;
BuildEnvironment _env;

class BuildEnvironment {
  /// The backend server.
  final String baseUrl;
  final BuildFlavor flavor;

  BuildEnvironment._init({this.flavor, this.baseUrl});

  /// Sets up the top-level [env] getter on the first call only.
  static void init({@required flavor, @required baseUrl}) =>
      _env ??= BuildEnvironment._init(flavor: flavor, baseUrl: baseUrl);
}

main_dev.dart

import 'package:flutter/material.dart';
import 'env.dart';
import 'app.dart';

void main() {
  BuildEnvironment.init(
      flavor: BuildFlavor.development, baseUrl: 'http://dev.example.com');
  assert(env != null);
  runApp(App());
}

main_prod.dart

import 'package:flutter/material.dart';
import 'env.dart';
import 'app.dart';

void main() {
  BuildEnvironment.init(
      flavor: BuildFlavor.production, baseUrl: 'http://example.com');
  assert(env != null);
  runApp(App());
}
  • Import env.dart to expose the env variable.
  • Run and build the app using the target option.
    flutter run -t lib/main_dev.dart
    flutter build -t lib/main_dev.dart

To integrate with VS Code, define launch configurations:

.vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "development",
      "program": "lib/main_dev.dart",
      "request": "launch",
      "type": "dart"
    },
    {
      "name": "production",
      "program": "lib/main_prod.dart",
      "request": "launch",
      "type": "dart"
    }
  ]
}

Release and Debug mode can now be acquired using:

const bool isProduction = bool.fromEnvironment('dart.vm.product');

Because this is a Constant it works with tree-shaking. So code like

if(isProduction) {
  // branch 1
} else {
  // branch 2
}

It would only include one of these two branches into production code depending on isProduction.

One way to do it: create a different main_<environment>.dart files in the lib/ directory of your project.

Each main_<environment>.dart contains the environment-specific configurations/values such as the different database names, etc. Each main_<environment>.dart then imports the actual application library and runs the application, passing in the environment’s values/configurations.

Then, choose which .dart file to build: flutter run -t lib/main_debug.dart

  • Starting from Flutter 1.17 you can use –dart-define to build your app with different compile-time variables. It works for both Dart and native layers.
  • In dart, you get these values with String.fromEnvironment for example. In that way, you won’t need to have tons of entry points and expose your environmental credentials.
  • Here is an article that explains more https://link.medium.com/ibuTsWHrk6
  • EZ Flutter is a collection of widgets, packages, and many more useful things, mixed up in a little framework. The aim is to make standard features available from scratch.

How to use it.

  • Create a json file under assets/cfg/$file.json
  • Add assets/cfg to your pubspec.yaml
  • Loading different configuration files at app start.
    import 'package:flutter/material.dart';
    import 'package:global_configuration/global_configuration.dart';
    
    void main() async{
      await GlobalConfiguration().loadFromAsset("app_settings");
      await GlobalConfiguration().loadFromAsset("env_dev_settings");
      runApp(MyApp());
    }
    class MyApp extends StatelessWidget {
      ...
    }
  • Using the configuration in your app:
    import 'package:flutter/material.dart';
    import 'package:global_configuration/global_configuration.dart';
    
    class CustomWidget extends StatelessWidget {
    
        CustomWiget(){
            // Access the config in the constructor
            print(GlobalConfiguration().getString("key1"); // prints value1
        }
    
        @override
         Widget build(BuildContext context) {
            // Access the config in the build method
            return new Text(GlobalConfiguration().getString("key2"));
         }
    }
  • Simply you can implement build variants:
    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.release
        }
        debug{
            applicationIdSuffix ".dev"
            signingConfig signingConfigs.debug
        }
       qa{
            applicationIdSuffix ".qa"
            signingConfig signingConfigs.qa
        }
    }
    
    productFlavors {
    
      dev {
          dimension "app"
          resValue "string", "app_name", "xyz Dev"
          applicationId "com.xyz.dev"
      }
      prod {
          dimension "app"
          resValue "string", "app_name", "xyz"
      }
    }
    • In iOS : Add configuration by selecting project->runner-> configuration add one more.

If you want to have a different app id for your app for your “dev” build, you could have this in the gradle file:

flavorDimensions "version"
productFlavors {
    dev {
        applicationIdSuffix ".dev"
        versionNameSuffix "-dev"
    }
}

Read more about gradle build variant configuration here.

    • Now you can run with this build variant with the command line:
      flutter run --flavor dev
    • If you are using Android Studio, you can set the build variant in the run configuration too:

      How to Build Different Versions of Flutter App
      How to Build Different Versions of Flutter App
  • import 'package:flutter/foundation.dart';

    And use the following const values:

    if (kReleaseMode) {
      // App is running in release mode. 
    } else if (kProfileMode) {
      // App is running in profile mode.
    } else if (kDebugMode) {
      // App is running in debug mode.
    } else if (kIsWeb) {
      // App is running on the web.
    }

    Create a file at the root of the project app_environment.dart. Use the kReleaseMode variable from the foundation.dart package to check for production mode.

    import 'package:flutter/foundation.dart';
    
    class AppEnvironment {
    
      String getApiURL() {
        if (kReleaseMode) {
          return 'PROD_API_URL';
        } else {
          return 'STAGING_API_URL';
        }
      }
    }

Conclusion:

Thanks for being with us on a Flutter Journey !!!

Drop your valuable suggestion/feedback to serve you much better.

Flutter Agency is our portal Platform dedicated to Flutter Technology and Flutter Developers. The portal is full of cool resources from Flutter like Flutter Widget GuideFlutter ProjectsCode libs and etc.

Flutter Agency is one of the most popular online portals dedicated to Flutter Technology. Daily thousands of unique visitors come to this portal to enhance their knowledge of Flutter.

Abhishek Dhanani

Written by Abhishek Dhanani

Abhishek Dhanani, a skilled software developer with 3+ years of experience, masters Dart, JavaScript, TypeScript, and frameworks like Flutter and NodeJS. Proficient in MySQL, Firebase, and cloud platforms AWS and GCP, he delivers innovative digital solutions.

Leave a comment

Your email address will not be published. Required fields are marked *


Discuss Your Project

Connect with Flutter Agency's proficient skilled team for your app development projects across different technologies. We'd love to hear from you! Fill out the form below to discuss your project.

Have Project For Us

Get in Touch

"*" indicates required fields

ready to get started?

Fill out the form below and we will be in touch soon!

"*" indicates required fields