diff --git a/packages/flutterfire_cli/lib/src/commands/config.dart b/packages/flutterfire_cli/lib/src/commands/config.dart index e01fa069..0cfaf8a6 100644 --- a/packages/flutterfire_cli/lib/src/commands/config.dart +++ b/packages/flutterfire_cli/lib/src/commands/config.dart @@ -108,10 +108,6 @@ class ConfigCommand extends FlutterFireCommand { return argResults!['out'] as String; } - String get appIDFilePath { - return 'firebase_app_id_file.json'; - } - String get iosAppIDOutputFilePrefix { return 'ios'; } @@ -120,6 +116,10 @@ class ConfigCommand extends FlutterFireCommand { return 'macos'; } + String get androidAppIDOutputFilePrefix { + return 'android'; + } + Future _promptCreateFirebaseProject() async { final newProjectId = promptInput( 'Enter a project id for your new Firebase project (e.g. ${AnsiStyles.cyan('my-cool-project')})', @@ -300,8 +300,8 @@ class ConfigCommand extends FlutterFireCommand { if (iosOptions != null) { final appIDFile = FirebaseAppIDFile( iosAppIDOutputFilePrefix, - appIDFilePath, - iosOptions.appId, + appId: iosOptions.appId, + firebaseProjectId: iosOptions.projectId, ); futures.add(appIDFile.write()); } @@ -309,8 +309,17 @@ class ConfigCommand extends FlutterFireCommand { if (macosOptions != null) { final appIDFile = FirebaseAppIDFile( macosAppIDOutputFilePrefix, - appIDFilePath, - macosOptions.appId, + appId: macosOptions.appId, + firebaseProjectId: macosOptions.projectId, + ); + futures.add(appIDFile.write()); + } + + if (androidOptions != null) { + final appIDFile = FirebaseAppIDFile( + androidAppIDOutputFilePrefix, + appId: androidOptions.appId, + firebaseProjectId: androidOptions.projectId, ); futures.add(appIDFile.write()); } diff --git a/packages/flutterfire_cli/lib/src/firebase/firebase_app_id_file.dart b/packages/flutterfire_cli/lib/src/firebase/firebase_app_id_file.dart index 69d3194f..f1dbfe20 100644 --- a/packages/flutterfire_cli/lib/src/firebase/firebase_app_id_file.dart +++ b/packages/flutterfire_cli/lib/src/firebase/firebase_app_id_file.dart @@ -25,8 +25,17 @@ import 'package:path/path.dart'; import '../common/exception.dart'; import '../common/utils.dart'; +const _defaultAppIdFileName = 'firebase_app_id_file.json'; +const _keyGoogleAppId = 'GOOGLE_APP_ID'; +const _keyFirebaseProjectId = 'FIREBASE_PROJECT_ID'; + class FirebaseAppIDFile { - FirebaseAppIDFile(this.outputDirectoryPath, this.fileName, this.appId); + FirebaseAppIDFile( + this.outputDirectoryPath, { + required this.appId, + required this.firebaseProjectId, + this.fileName = _defaultAppIdFileName, + }); final StringBuffer _stringBuffer = StringBuffer(); @@ -35,23 +44,35 @@ class FirebaseAppIDFile { final String fileName; final String appId; + final String firebaseProjectId; Future write() async { - // ignore: avoid_slow_async_io - final directoryExists = await Directory(outputDirectoryPath).exists(); - if (!directoryExists) { + if (!Directory(outputDirectoryPath).existsSync()) { throw PlatformDirectoryDoesNotExistException(outputDirectoryPath); } + final appIDFilePath = joinAll([outputDirectoryPath, fileName]); final outputFile = File(joinAll([Directory.current.path, appIDFilePath])); + if (outputFile.existsSync() && !isCI) { - final shouldOverwrite = interact.Confirm( - prompt: - 'Generated FirebaseAppID file ${AnsiStyles.cyan(appIDFilePath)} already exists, do you want to override it?', - defaultValue: true, - ).interact(); - if (!shouldOverwrite) { - throw FirebaseAppIDAlreadyExistsException(appIDFilePath); + final existingFileContents = await outputFile.readAsString(); + final existingFileContentsAsJson = + json.decode(existingFileContents) as Map; + final existingAppId = + existingFileContentsAsJson[_keyGoogleAppId] as String; + final existingFirebaseProjectId = + existingFileContentsAsJson[_keyFirebaseProjectId] as String; + // Only prompt overwrite if values are different. + if (existingAppId != appId || + existingFirebaseProjectId != firebaseProjectId) { + final shouldOverwrite = interact.Confirm( + prompt: + 'Generated FirebaseAppID file ${AnsiStyles.cyan(appIDFilePath)} already exists (for app id "$existingAppId" on Firebase Project "$existingFirebaseProjectId"), do you want to override it?', + defaultValue: true, + ).interact(); + if (!shouldOverwrite) { + throw FirebaseAppIDAlreadyExistsException(appIDFilePath); + } } } _writeHeaderAndAppID(outputFile.path); @@ -61,9 +82,11 @@ class FirebaseAppIDFile { void _writeHeaderAndAppID(String outputFile) { final fileData = { 'file_generated_by': 'FlutterFire CLI', - 'purpose': 'FirebaseAppID for this Firebase app in this directory', - 'GOOGLE_APP_ID': appId + 'purpose': + 'FirebaseAppID & ProjectID for this Firebase app in this directory', + _keyGoogleAppId: appId, + _keyFirebaseProjectId: firebaseProjectId, }; - _stringBuffer.write(json.encode(fileData)); + _stringBuffer.write(const JsonEncoder.withIndent(' ').convert(fileData)); } } diff --git a/packages/flutterfire_cli/lib/src/firebase/firebase_configuration_file.dart b/packages/flutterfire_cli/lib/src/firebase/firebase_configuration_file.dart index 787586b9..a20e6e8f 100644 --- a/packages/flutterfire_cli/lib/src/firebase/firebase_configuration_file.dart +++ b/packages/flutterfire_cli/lib/src/firebase/firebase_configuration_file.dart @@ -48,18 +48,26 @@ class FirebaseConfigurationFile { Future write() async { final outputFile = File(joinAll([Directory.current.path, outputFilePath])); + + // Write buffer early so we can string compare contents if file exists already. + _writeHeader(); + _writeClass(); + final newFileContents = _stringBuffer.toString(); + if (outputFile.existsSync() && !isCI) { - final shouldOverwrite = interact.Confirm( - prompt: - 'Generated FirebaseOptions file ${AnsiStyles.cyan(outputFilePath)} already exists, do you want to override it?', - defaultValue: true, - ).interact(); - if (!shouldOverwrite) { - throw FirebaseOptionsAlreadyExistsException(outputFilePath); + final existingFileContents = await outputFile.readAsString(); + // Only prompt overwrite if contents have changed. + if (existingFileContents != newFileContents) { + final shouldOverwrite = interact.Confirm( + prompt: + 'Generated FirebaseOptions file ${AnsiStyles.cyan(outputFilePath)} already exists, do you want to override it?', + defaultValue: true, + ).interact(); + if (!shouldOverwrite) { + throw FirebaseOptionsAlreadyExistsException(outputFilePath); + } } } - _writeHeader(); - _writeClass(); outputFile.writeAsStringSync(_stringBuffer.toString()); }