My approach to multiple environments - use multiple projects, and a .env
file to determine which to use.
Project setup
- I used Flutterfire CLI to set up a Firebase project:
flutterfire configure
- After the project is created, I renamed the config files to represent the environment:
mv android/app/google-services.json android/app/google-services-<env>.json
mv ios/firebase_app_id_file.json ios/firebase_app_id_file-<env>.json
mv lib/firebase_options.dart lib/firebase_options_<env>.dart
Repeat steps 1-2, for each environment you need.
Environment variable setup
- Used flutter_dotenv to load an environment variable used to determine the environment:
.env
:
# Set choose environment. Options: production, stage, etc...
ENVIRONMENT=production
- Don't forget to add
.env
to pubspec.yaml
flutter:
assets:
- .env
Connect the environment set in .env
- Update
main.dart
to import env configs, and flutter_dotenv
:
main.dart:
import 'firebase_options_prod.dart' as prod;
import 'firebase_options_stage.dart' as stage;
import 'package:flutter_dotenv/flutter_dotenv.dart';
- Load
.env
the following line before you initialize Firebase:
main.dart:
await dotenv.load(fileName: '.env');
- Pass in the appropriate config based on the value
ENVIRONMENT
:
main.dart:
await Firebase.initializeApp(
options:
dotenv.env['ENVIRONMENT'] == 'stage' ? stage.DefaultFirebaseOptions.currentPlatform :
prod.DefaultFirebaseOptions.currentPlatform);
Here is main()
in its entirety:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await dotenv.load(fileName: '.env');
try {
await Firebase.initializeApp(
options:
dotenv.env['ENVIRONMENT'] == 'stage' ? stage.DefaultFirebaseOptions.currentPlatform :
prod.DefaultFirebaseOptions.currentPlatform);
} catch(exception) {
if(exception is FirebaseException && exception.code == 'duplicate-app') {
debugPrint("Did you forget to recompile the Runner app, after changing environments?");
}
rethrow;
}
runApp(const MyApp());
}
Note the try/catch/rethrow added in. I added this because when you change environments, you cannot hot restart. You need to recompile the runner app. If you do not, and then you change environments, Firebase throw an error that looks like this:
Unhandled Exception: [core/duplicate-app] A Firebase App named "[DEFAULT]" already exists
So I wanted an easy reminder of why I might see that error.