Seth Ladd
Seth Ladd

Reputation: 120579

How do I build different versions of my Flutter app for qa/dev/prod?

I am building a Flutter app, and I have variables with different values for different environments (QA, dev, prod, etc). What's a good way to organize my app so I can easily make a build for QA, dev, prod, and other environments?

Upvotes: 64

Views: 39051

Answers (9)

CopsOnRoad
CopsOnRoad

Reputation: 267704

import 'package:flutter/foundation.dart';

And use 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.
}

Upvotes: 11

Yuchen
Yuchen

Reputation: 33036

The cleaner way to do this is through Build Flavors.

As a quick example, 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 command line:

flutter run --flavor dev

If you are using Android Studio, you can set the build variant in the Run configuration too:

enter image description here

Read more about iOS configuration on this blog. And official flutter documentation about build flavours.

Upvotes: 6

Yashwardhan Pauranik
Yashwardhan Pauranik

Reputation: 5566

Create a file at the root of the project app_environment.dart. Use the kReleaseMode variable from 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';
    }
  }
}

Upvotes: 3

tatsuDn
tatsuDn

Reputation: 2429

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 or entry points and expose your environment credentials

Here is an article that explains more https://link.medium.com/ibuTsWHrk6

Upvotes: 15

siva kumar
siva kumar

Reputation: 2925

Simply you can implement build variants.

In android:

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

Upvotes: 4

Ephenodrom
Ephenodrom

Reputation: 1893

Update July 2019 :

I wrote a Package that integrates the Flutter Global Config.

EZ Flutter is a collection of widgets, packages and many more usefull things, mixed up in little framework. The aim is to make standard features available from scratch.

Github : https://github.com/Ephenodrom/EZ-Flutter

dependencies:
  ez_flutter: ^0.2.0

Check out the documentation how using different configurations works.

https://github.com/Ephenodrom/EZ-Flutter/blob/master/documentation/APPLICATION_SETTINGS.md

++++ OLD ANSWER ++++

Additional information :

I had the same problem and used the solution suggested by Seth Ladd. Therefore I also needed different configuration for each app version (dev / prod ) and i don't want to write the configuration in the main_dev.dart or in the main_prod.dart file.

I wrote a simple flutter package that deals with having seperated configuration files and load them at app startup. The configuration is then available at each line of code in your app.

https://github.com/Ephenodrom/Flutter-Global-Config

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"));
     }
}

Upvotes: 2

Günter Zöchbauer
Günter Zöchbauer

Reputation: 657486

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
}

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

Upvotes: 26

Jacob Phillips
Jacob Phillips

Reputation: 9264

Building on Seth's idea, here's an example that sets up a global representing the BuildEnvironment named env.

env.dart

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"
    }
  ]
}

I had originally set out to use command line arguments passed to Dart's main function, but I don't think args can currently be passed on the command line with flutter run or flutter build, although VS Code and Android Studio both support passing args to main. It also seems build flavor as a command line arg to main is not appropriate since args can be passed after the build process.

Upvotes: 49

Seth Ladd
Seth Ladd

Reputation: 120579

One way to do it: create 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

Upvotes: 27

Related Questions