Reputation: 8624
For example, building a client for an API, like Twitch.
In a Dart CLI binary, I could use a generic environment variable, or a Dart definition variable. For example, using both as fallbacks:
main() {
String clientId =
// dart -dCLIENT_ID='abc bin/example.dart
// This is considered "compiled-into" the application.
const String.fromEnvironment('CLIENT_ID') ??
// CLIENT_ID='abc' dart bin/example.dart
// This is considered a runtime flag.
Platform.environment['CLIENT_ID'];
// Use clientId.
}
Does Flutter have a way of setting either/both of these, specifically...
Happy to help with some docs once I figure out how :)
Upvotes: 120
Views: 158194
Reputation: 594
If you're using the Flutter version >= 3.7 you can pass the environment variables in 2 ways either by argument or by a config file. for example:
flutter run --dart-define=BASE_URL=http://localhost:3000
Or you can create a file such as env.json and set your all desired variables in it for example:
{
"BASE_URL": "http://localhost:3000",
"TEST_USER": "test_user"
}
and then pass the file:
flutter run --dart-define-from-file=env.json
And if your Flutter version is < 3.7 you have only the first option
Upvotes: 13
Reputation: 1533
Flutter introduced environment variables at compile-time using the --dart-define
argument. Where you have more than one environment variable, using the --dart-define-from-file
argument is advisable.
For a single environment variable, follow the below:
flutter run --dart-define=VAR_NAME=SOME_VALUE
Where there is more than one environment variable, follow the below steps:
{
"VAR_A": someValue,
"VAR_B": anotherValue
}
flutter run --dart-define-from-file=config.json
where config.json is the created JSON file containing the variables.
To retrieve these variables from your code, any of the following works depending on the data type:
const VAR_A = String.fromEnvironment('VAR_A', defaultValue: 'SOME_DEFAULT_VALUE');
const VAR_B = int.fromEnvironment('VAR_B', defaultValue: 1);
const VAR_C = bool.fromEnvironment('VAR_C', defaultValue: false);
It should be noted that there are no fromEnvironment constructors for double. The above arguments can also be used with the flutter build
command.
The article here explains how to do this in-depth.
Upvotes: 6
Reputation: 179
If you have multiple environment variables, use option --dart-define-from-file=env.json
.
Ex:
flutter build web --dart-define-from-file=env.json
or
flutter run --dart-define-from-file=env_dev.json
Place env.json in the root, where pubspec.yaml resides.
Sample json files
env.json
{ "backend_url": "https://server.com" }
env_dev.json
{ "backend_url": "https://dev.server.com" }
Sample use:
const backendUrl = String.fromEnvironment('backend_url', defaultValue: 'SOME_DEFAULT_VALUE');
Upvotes: 17
Reputation: 1
although above answers are correct coming from python and reactjs I used dotenv and found the same for flutter to load .env file https://pub.dev/packages/dotenv
Upvotes: 0
Reputation: 2753
I do agree
with the answer posted by @tatsuDn but I wanted to provide a solution that loads your environment variables from a .env file.
First create a .env
file in the root folder of your project.
Ensure that you add the file to your pubspec.yaml
and [git] ignore
it.
Here is how your .env
file should look
API_KEY=sampleapikey
# This line is a comment
# The white line above will be ignored
HEADER=sampleapiheader
ANOTHER_UNIQUE_KEY=theValueOfThisKey
KEY_CONTAINS_#=*234*5#
KEY_CONTAINS_EQUALS=IP8iwe=0&
Here is how your assets section to look like.
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/
- assets/flags/
- .env
Finally, load your environment variable by reading and parsing the .env
file to get a Map<String, String>
that contains your key value pairs.
Future<Map<String, String>> parseStringToMap({String assetsFileName = '.env'}) async {
final lines = await rootBundle.loadString(assetsFileName);
Map<String, String> environment = {};
for (String line in lines.split('\n')) {
line = line.trim();
if (line.contains('=') //Set Key Value Pairs on lines separated by =
&&
!line.startsWith(RegExp(r'=|#'))) {
//No need to add emty keys and remove comments
List<String> contents = line.split('=');
environment[contents[0]] = contents.sublist(1).join('=');
}
}
return environment;
}
You can put a quick button in your code to test that the environment variables are being loaded properly.
ElevatedButton(
onPressed: () async {
final env = await parseStringToMap(assetsFileName: '.env');
print(env);
},
child: Text('Print Environment Variables')
),
Here is the output from the .env file above.
>>>I/flutter ( 7182): {API_KEY: sampleapikey, HEADER: sampleapiheader, ANOTHER_UNIQUE_KEY: theValueOfThisKey, KEY_CONTAINS_#: *234*5#, KEY_CONTAINS_EQUALS: IP8iwe=0&}
Notes: You will need to rerun the app (not hot reload) so that the .env
assets is loaded.
You can also just load your variables in a json file[this may be helpful when you have non string environemental variables and you dont want to parse string.
To avaoid IO, it is a good Idea to just load the environment variables once and access them through out the app using service locators like GetIt
.
Upvotes: 7
Reputation: 29038
flutter run
)flutter run --dart-define=EXAMPLE_API_ENDPOINT=https://api.example.com/
flutter build
)My app wasn't letting users log in I realized that environment variables were empty strings in the app, instead of their actual values š .
flutter build ipa --dart-define=EXAMPLE_API_ENDPOINT=https://api.example.com/
flutter build apk --dart-define=EXAMPLE_API_ENDPOINT=https://api.example.com/
--dart-define
documentationFrom the flutter run --help
or flutter build ipa --help
, the --dart-define
shows:
Additional key-value pairs that will be available as
constants from the String.fromEnvironment, bool.fromEnvironment,
int.fromEnvironment, and double.fromEnvironment constructors.
Multiple defines can be passed by repeating "--dart-define"
multiple times.
Upvotes: 17
Reputation: 2882
I use simple shell script to generate dart defines. In my app there are 3 build flavors: dev
, staging
and prod
. Environment variables were defined in a regular .env
file.
env/
āāā dev.env
āāā prod.env
āāā staging.env
Here is the script to generate dart-defines
from .env
file.
#!/bin/bash
# scripts/generate_dart_defines.sh
case "$1" in
"dev") INPUT="env/dev.env"
;;
"staging") INPUT="env/staging.env"
;;
"prod") INPUT="env/prod.env"
;;
*)
echo "Missing arguments [dev|staging|prod]"
exit 1
;;
esac
while IFS= read -r line
do
DART_DEFINES="$DART_DEFINES--dart-define=$line "
done < "$INPUT"
echo "$DART_DEFINES"
Here is the script to trigger a build.
#!/bin/bash
# build.sh
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then
echo -e "Missing arguments: [apk|appbundle|ios] [release|debug|profile] [dev|staging|prod]"
# invalid arguments
exit 128
fi
DART_DEFINES=$(scripts/generate_dart_defines.sh $3)
if [ $? -ne 0 ]; then
echo -e "Failed to generate dart defines"
exit 1
fi
echo -e "artifact: $1, type: $2, flavor: $3\n"
echo -e "DART_DEFINES: $DART_DEFINES\n"
eval "flutter build $1 --$2 --flavor $3 $DART_DEFINES"
The script accepts 3 arguments. First one is the artifact apk
, appbundle
or ios
. Second one is the build type release
, debug
or profile
. Third one is the build flavor, dev
, staging
or prod
.
./build.sh apk release prod
Please note that you also required to configure android and ios for different build flavors separately. https://developer.android.com/studio/build/build-variants
https://shockoe.com/ideas/development/how-to-setup-configurations-and-schemes-in-xcode/
Upvotes: 15
Reputation: 2439
Starting from Flutter 1.17 you can define compile-time variables if you want to.
To do so just use --dart-define
argument during flutter run
or flutter build
If you need to pass multiple key-value pairs, just define --dart-define
multiple times:
flutter run --dart-define=SOME_VAR=SOME_VALUE --dart-define=OTHER_VAR=OTHER_VALUE
and then, anywhere in your code you can use them like:
const SOME_VAR = String.fromEnvironment('SOME_VAR', defaultValue: 'SOME_DEFAULT_VALUE');
const OTHER_VAR = String.fromEnvironment('OTHER_VAR', defaultValue: 'OTHER_DEFAULT_VALUE');
Also, they can be used in native layers too.
Here is an article that explains more.
Upvotes: 175
Reputation: 268534
Create a class:
import 'package:flutter/foundation.dart';
class AppUtils {
static String get clientId {
if (kDebugMode) return 'debug_id';
else if (kProfileMode) return 'profile_id';
else if (kReleaseMode) return 'production_id';
else if (kIsWeb) return 'web_mode_id';
throw ArgumentError('No mode detected');
}
}
Usage:
var id = AppUtils.clientId;
Upvotes: -4
Reputation: 607
Since I was trying to solve this as well and encountered this thread I just wanted to add this for people looking for a solution in the future... If all you're looking for is PROD/DEV environments there is now a supported way of getting if the app is in production or not:
const bool isProduction = bool.fromEnvironment('dart.vm.product');
As suggested by:
https://twitter.com/FlutterDev/status/1048278525432791041
https://github.com/flutter/flutter/issues/4014
Upvotes: 32
Reputation: 3522
For configuration a common pattern I've seen is to use separate main files instead. i.e.
flutter run -t lib/production_main.dart
and
flutter build apk -t lib/debug_main.dart
And then in those different main files set up the configurations desired.
In terms of reading ids, you can do that from arbitrary assets https://flutter.io/assets-and-images/.
I believe it is possible in Flutter to read from the environment as you suggest, however I don't know how to set those environment variables on iOS or Android.
Upvotes: 37