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?
问题:
回答1:
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 theenv
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.
回答2:
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
回答3:
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
回答4:
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"));
}
}
回答5:
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
}
}
In iOS :
add configuration by selecting project->runner-> configuration add one more