Support for multiple scheme dev, staging, prod

Could you give some more details on what exactly it is you're looking for?

I have the same requirement so I can comment on this.
My app is configured to use multiple flavors.
As such, I have three sets of package_names / bundle IDs:

Dev: com.codewithandrea.flutterfire-flavors.dev
Staging: com.codewithandrea.flutterfire-flavors.stg
Prod: com.codewithandrea.flutterfire-flavors

Here's how they look like on the Xcode build settings:

And here's how they're set up inside android/app/build.gradle
    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.codewithandrea.flutterfire_flavors"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    ...

    flavorDimensions "default"
    productFlavors {
        production {
            dimension "default"
            applicationIdSuffix ""
            manifestPlaceholders = [appName: "Flutterfire Flavors"]
        }
        staging {
            dimension "default"
            applicationIdSuffix ".stg"
            manifestPlaceholders = [appName: "[STG] Flutterfire Flavors"]
        }
        development {
            dimension "default"
            applicationIdSuffix ".dev"
            manifestPlaceholders = [appName: "[DEV] Flutterfire Flavors"]
        }
    }

Accordingly, I want to have a separate Firebase project for each flavor.
I tried to run flutterfire configure on my project, but by default it only works with one Firebase project and doesn't take into account the platform-specific configuration.
Here's a log:
✔ Select a Firebase project to configure your Flutter application with · <create a new project>
✔ Enter a project id for your new Firebase project (e.g. my-cool-project) · flutterfire-flavors-dev
i New Firebase project flutterfire-flavors-dev created succesfully.
✔ Which platforms should your configuration support (use arrow keys & space to select)? · android, ios, web, macos
i Firebase android app com.codewithandrea.flutterfire_flavors is not registered on Firebase project flutterfire-flavors-dev.
i Registered a new Firebase android app on Firebase project flutterfire-flavors-dev.

✔ Which ios bundle id do you want to use for this configuration, e.g. 'com.example.app'? · com.codewithandrea.flutterfire-flavors.dev
i Firebase ios app com.codewithandrea.flutterfire-flavors.dev is not registered on Firebase project flutterfire-flavors-dev.
i Registered a new Firebase ios app on Firebase project flutterfire-flavors-dev.
✔ Which macos bundle id do you want to use for this configuration, e.g. 'com.example.app'? · com.codewithandrea.flutterfire-flavors
i Firebase macos app com.codewithandrea.flutterfire-flavors is not registered on Firebase project flutterfire-flavors-dev.
i Registered a new Firebase macos app on Firebase project flutterfire-flavors-dev.
i Firebase web app flutterfire_flavors (web) is not registered on Firebase project flutterfire-flavors-dev.
i Registered a new Firebase web app on Firebase project flutterfire-flavors-dev.

Note how it detected com.codewithandrea.flutterfire_flavors as the Android app (non-flavored version) and it asked for the bundle ID on iOS and macOS.
How I would like this to work

flutterfire should detect if the app is configured with multiple flavors, and ask if I want to use/create a separate Firebase project for each.
then it should create firebase_options_dev.dart, firebase_options_staging.dart, firebase_options_prod.dart files that can be imported in each of the entry points (in my case I have main_development.dart, main_staging.dart, main_production.dart).

Note: I use very_good_cli to automate the process of creating an app with multiple flavors, but the same applies if multiple flavors are created manually.
As it stands, the only reliable way of getting this to work is to:

create 3 mock Flutter projects to match the package names of each of my desired flavors
run flutterfire configure on each
rename and copy the generated firebase_options.dart into the main Flutter app for each flavor

It can be done, but it's error prone and the whole point of flutterfire is to automate all this configuration.
Any serious project would use multiple flavors, so I believe this is a very important feature to add.

This is technically possible now already with the CLI using the CLI flags, e.g.:
flutterfire config \
  --out=lib/firebase_options_dev.dart \
  --ios-bundle-id=com.codewithandrea.flutterfire-flavors.dev \
  --macos-bundle-id=com.codewithandrea.flutterfire-flavors.dev \
  --android-app-id=com.codewithandrea.flutterfire-flavors.dev

So the options are already in place - albeit maybe a little manual
If someone would like to PR to make this less manual then please do :)

@Salakar that's great! That already takes much of the pain away as it needs to be run 3 times but at least it can be automated.

I'm going to close this now since I think this is essentially covered now with the above flags and along with the recent addition of the --yes flag (to skip prompts and accept defaults). Meaning this can be automated, e.g. defining commands in melos scripts to switch environments

@Salakar that is not a solution, as there is no documentation describing how to do that, nor it seems trivial.
Running flutterfire config also creates a firebase_app_id_file.json file that needs to exist in each of android and ios folder. This file doesn't seem to allow for flavors, so I can't have them scoped like firebase_app_id_file_development.json.

I agree with @JCQuintas. Plus those files were not generated by the first version of FlutterFire CLI, and when I delete google_services.json and the corresponding plugin configuration from android/app/build.gradle, and the firebase_app_id_file.json file from ios, everything seems to work fine without them. Why were those files added by default? What is their purpose? And if they are absolutely useful, you need to add command-line arguments to make it possible to override where these files will be generated so that they don't overwrite the last version when I run flutterfire configure for each of my flavor projects.

Unfortunately these firebase_app_id_file.json files and .gradle file updates are required for native builds if you want certain plugins (like Analytics, Crashlytics & Performance) to function correctly on Android, iOS & macOS. Since these interact with native builds there isn't really a way to make them environment specific since the CLI would be unware of your Android/iOS build targets etc. Open to suggestions/pull requests on these.
Having said that, in the latest release I've just shipped two new flags (hidden), --no-apply-gradle-plugins and --no-app-id-json - which will disable these files being generated/changed should you need to opt-out, though I'd caution against doing so unless you know what you're doing with configuring the native parts of Android / iOS to work properly with the Firebase services mentioned above.

The first thing is to document why those files can be necessary. For example, in the CLI documentation, on the line about --[no-]apply-gradle-plugin there should be a mention explaining why you might not need to apply the gradle plugin and create the google-services.json file. There are a lot of projects that only use firebase core, auth and firestore, but not analytics, crashlytics and performance.
Second of all, there should be an equivalent option to this one for the app-id-json and that's great that you added that. Is it already in the current version, but just undocumented?
You could also make it so that flutterfire configure doesn't generate any of those files by default, and then add a command to flutterfire that adds those files for native plugins, something like flutterfire configure-native-plugins, but maybe that's overkill.
Then the most important thing is to make is possible to customize the path and the name of those files, just like -out lets us do it for firebase_options.dart. I use that already to have 3 versions of this file in my project, one for each environment/flavor, that I import into each of my main.darts. In Android, google-services-json could be stored in flavor-specific subdirectories (android/app/src/dev or android/app/src/prod instead of the default android/app/src/main) so that Gradle picks up on the right version depending on the flavor. So maybe a command-line parameter like -android-native-out that accepts a full path for google-services.json.
And finally, I would like a command line parameter to customize where the app id json file is generated for ios, path and file name as well, which would allow me to have different versions of that file for my different environments. And then because Firebase native libraries look for this file in a specific place with a specific name, I can have a script in my XCode build pipeline that picks up the proper version of the file and copies it where Firebase is expecting it to be. That's already what we did for flavor builds before. Agreed, you don't need to document that process in the CLI documentation, but giving that option makes it more flexible.
By the way, I'm preparing a step-by-step tutorial on how to flavorize a Flutter project including web support and firebase support, so if those options are added, I will also document them there.

By the way, I just tried to add the --no-apply-gradle-plugin flag, as described in the CLI documentation, but I got an error: Could not find an option named "no-apply-gradle-plugin"
And indeed, it is not documented in flutterfire help configure

By the way, I just tried to add the --no-apply-gradle-plugin flag, as described in the CLI documentation, but I got an error: Could not find an option named "no-apply-gradle-plugin"
And indeed, it is not documented in flutterfire help configure

--no-apply-gradle-plugins (plural on plugins) there's an update for the docs waiting to fix the docs but we're in a docs change freeze right now sorry 🙈
Thanks for all the input previously also, I can certainly add options to change the output paths for both json files so let me look into that, the only caveat to this is that we need to note on the CLI that if you do this it won't work by default and you shouldn't do it unless you know what you're doing.
--no-app-id-json also exists in current version released yesterday, flags are hidden currently so won't show in --help.  I wonder perhaps if these two flags should become one flag, something like --[no-]native-integration since effectively similar just ones for android and one ios

@Salakar  In our app we have defined two flavors (ios schemes) but only one Firebase project. How can we achieve to have firebase_app_id_file.json per scheme?
One of the older project we have defined custom Build Phase which will copy correct GoogleServices.plist into project based on current scheme. Do we need something similar?

For all who are searching for a solution (also working in pipelines):
# Install Firebase-CLI
curl -sL firebase.tools | bash

# Install FlutterFire CLI
flutter pub global activate flutterfire_cli

# Configure FlutterFire for ios, android and web
flutterfire configure -y --project MYAPP-$SCHEME --android-app-id=$BUNDLE_ID --ios-bundle-id=$BUNDLE_ID --macos-bundle-id=$BUNDLE_ID --platforms=android,ios,web

Flutter Flavors are a feature of flutter overall that the CLI is completely oblivious to at the moment. We are going to have to stay on an older version of firebase, but as customers of firebase this is a major blocker for being able to adopt some of the new features.

If you check out this article that I published recently, you will see that it's possible to work around it. The article is now also referenced in the documentation.

@sarbogast this doesn't solve the issue with firebase_app_id_file.json file being not flavoured.

I used https://medium.com/@animeshjain/build-flavors-in-flutter-android-and-ios-with-different-firebase-projects-per-flavor-27c5c5dac10b method to copy google-services.json with the old method. Maybe, something similar should work for the firebase_app_id_file.json.
Something like :
`environment="default"
Regex to extract the scheme name from the Build Configuration
We have named our Build Configurations as Debug-dev, Debug-prod etc.
Here, dev and prod are the scheme names. This kind of naming is required by Flutter for flavors to work.
We are using the $CONFIGURATION variable available in the XCode build environment to extract
the environment (or flavor)
For eg.
If CONFIGURATION="Debug-prod", then environment will get set to "prod".
if [[ $CONFIGURATION =~ -([^-]*)$ ]]; then
environment=${BASH_REMATCH[1]}
fi
echo $environment
Name and path of the resource we're copying
FIREBASEPPID_INFO_PLIST=firebase_app_id_file.json
FIREBASEPPID_INFO_FILE=${PROJECT_DIR}/config/${environment}/${FIREBASEPPID_INFO_PLIST}
Make sure firebase_app_id_file.json exists
echo "Looking for ${FIREBASEPPID_INFO_PLIST} in ${FIREBASEPPID_INFO_FILE}"
if [ ! -f $FIREBASEPPID_INFO_FILE ]
then
echo "No firebase_app_id_file.json found. Please ensure it's in the proper directory."
exit 1
fi
Get a reference to the destination location for the firebase_app_id_file.json
This is the default location of firebase_app_id_file.json file
PLIST_DESTINATION=${PROJECT_DIR}
echo "Will copy ${FIREBASEPPID_INFO_PLIST} to final destination: ${PLIST_DESTINATION}"
Copy over the prod firebase_app_id_file.json for Release builds
cp "${FIREBASEPPID_INFO_FILE}" "${PLIST_DESTINATION}"`
Also instead of executed at the build phase, it should probably be place in the Pre-Action of the Scheme.

@Salakar my app was configured manually last year to use FlutterFire. At each release I always take a look at the Quick Start guide, to see if I need to change some configuration, json, gradle, etc.
On the last release the docs were migrated and updated to only have a CLI option for the configurations, but my app has several whitelabel versions and stages, which I can't find a documentation on how to configure those.
I think there are 2 scenarios here:

Multiple Apps on the same project. This will happen with whitelabel apps, where they have different package ids/bundle ids, but they all use the same crashlytics or remote config.

Multiple Apps on different projects. This will happen with different stages of release (development, tests, production), so we could have a database segregation and not impact customers if we are playing with the database.

The CLI must support both of these scenarios, which can include flavors and dimensions on Android or Schemes and Targets on iOS.
For now I just updated the packages versions on pubspec.yaml, but since I can't run the CLI and have dart initialization, I imagine my Crashlytics reports won't be optimized for Flutter.

I am not sure how those commands will deal with flavors, since we need multiple json/plist in different native folders. Example: one json in the Android prod folder and another in the dev folder.

All that is needed if for the command to let us customize the path and/or name of those files so that we can then add our own scripts to copy the right version to the location and name expected by the native plugins, just like we used to do with legacy configuration.

@bizz84  what's your thoughts on this now?

For what it's worth, I resolved this issue by running flutterfire config multiple times. if you run flutterfire configure once for each flavor, and then move the resulting google-services.json into android/app/src/${flavorName}, then the build succeeds for each flavor. A big caveat here is that I have only tested this on Android so far, not on iOS. I haven't looked into what steps will be necessary to get the different flavors working on iOS with flutterfire.

For android it does work like you said @sdstolworthy but for iOS the cli only outputs one file ios/firebase_app_id_file.json and it will overwrite it each time. We can manually fix it for iOS.
There is a warning printed when doing pod install:
Warning: firebase_app_id_file.json file does not exist. This may cause issues in upload-symbols. If this error is unexpected, try running flutterfire configure again.

I guess it can be ignored as long as you're sure you have set things up correctly.
What I did:

Ran the configure command multiple times, making sure to copy the ios/firebase_app_id_file.json file into my respective flavor folder each time. This is the same folder I store my GoogleService-Info.plist file for each flavor.

ios/Runner/Firebase/Prod/firebase_app_id_file.json
ios/Runner/Firebase/Sandbox/firebase_app_id_file.json

Added an xcode run script build phase which copies the correct firebase_app_id_file.json file into the root ios/ folder, just like the one for GoogleService-Info.plist works.
In my main.dart I use package_info_plus to know my package name to determine what flavor is running and configure firebase with the correct file accordingly:

import 'package:app/firebase_options_prod.dart';
import 'package:app/firebase_options_sandbox.dart';
import 'package:package_info_plus/package_info_plus.dart';

Future<void> main() async {
  late final PackageInfo packageInfo;
  try {
    packageInfo = await PackageInfo.fromPlatform();
  } catch (e, s) {
    /// Fallback value
    packageInfo = PackageInfo(
      appName: 'MyApp',
      packageName: 'com.myapp.prod',
      buildNumber: '0',
      version: '0.0.0',
    );
  }

  final isSandbox = packageInfo.packageName == 'com.myapp.sandbox';

  await Firebase.initializeApp(
  options: isSandbox
      ? firebase_sandbox.DefaultFirebaseOptions.currentPlatform
      : firebase_prod.DefaultFirebaseOptions.currentPlatform,
  );
}

Here is my run script I used:
# Name of the resource we're selectively copying
FIREBASE_APP_ID_FILE=firebase_app_id_file.json

# Get references to sandbox and prod versions of firebase_app_id_file.json
# NOTE: These should only live on the file system and should NOT be part of the target (since we'll be adding them to the target manually)
FIREBASE_APP_ID_FILE_SANDBOX=${PROJECT_DIR}/${TARGET_NAME}/Firebase/Sandbox/${FIREBASE_APP_ID_FILE}
FIREBASE_APP_ID_FILE_PROD=${PROJECT_DIR}/${TARGET_NAME}/Firebase/Prod/${FIREBASE_APP_ID_FILE}

# Make sure the sandbox version of firebase_app_id_file.json exists
echo "Looking for ${FIREBASE_APP_ID_FILE} in ${FIREBASE_APP_ID_FILE_SANDBOX}"
if [ ! -f $FIREBASE_APP_ID_FILE_SANDBOX ]
then
    echo "No sandbox firebase_app_id_file.json found. Please ensure it's in the proper directory."
    exit 1
fi

# Make sure the prod version of firebase_app_id_file.json exists
echo "Looking for ${FIREBASE_APP_ID_FILE} in ${FIREBASE_APP_ID_FILE_PROD}"
if [ ! -f $FIREBASE_APP_ID_FILE_PROD ]
then
    echo "No prod firebase_app_id_file.json found. Please ensure it's in the proper directory."
    exit 1
fi

# Get a reference to the destination location for firebase_app_id_file.json
FILE_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
echo "Will copy ${FIREBASE_APP_ID_FILE} to final destination: ${FILE_DESTINATION}"

# Copy over the correct firebase_app_id_file.json for the current build configuration
if [ "${CONFIGURATION}" == "Debug-prod" ] || [ "${CONFIGURATION}" == "Release-prod" ] || [ "${CONFIGURATION}" == "Profile-prod" ]
then
    echo "Using ${FIREBASE_APP_ID_FILE_PROD}"
    cp "${FIREBASE_APP_ID_FILE_PROD}" "${FILE_DESTINATION}"
elif [ "${CONFIGURATION}" == "Debug-sandbox" ] || [ "${CONFIGURATION}" == "Release-sandbox" ] || [ "${CONFIGURATION}" == "Profile-sandbox" ]
then
    echo "Using ${FIREBASE_APP_ID_FILE_SANDBOX}"
    cp "${FIREBASE_APP_ID_FILE_SANDBOX}" "${FILE_DESTINATION}"
else
    echo "Error: invalid configuration specified: ${CONFIGURATION}"
fi

At build/run time, it all works as expected because there's only one ios/firebase_app_id_file.json file and it's in the correct spot at build time thanks to the run script. Depending which flavor I select, it copies the right one into place just like it does for the GoogleService-Info.plist file.
This is a tough thing to solve in the cli tool because flavors are by design such a flexibly-implemented thing - people use all sorts of different approaches. I think there might just need to be a good doc page outlining the approach for setting it up for flavors and it's up to the user to adapt it to their specific implementation.

Hello,
One of the things I'm missing right here is the option to create a "secured" prod version of the firebase_options.dart file. I mean, I've managed to successfully setup a project using the flutterfire cli with the configure command. However, this just adds a dart file with my keys in plain text. This is obviously fine for local development, but not very recommended for the production build. I would love to have an option where the FirebaseOptions class can read the encrypted keys from a file .json or some other file (e.g. the google-services.json file that can be saved encrypted in a CI/CD tool).

HI @MdeBruin93, the google-service.json does not contain any confidential data. It's not a problem to commit this and publish it. Especially, for web apps it's super easy to access the google-service.json. So you don't need to worry about to make the google-service.json "secure". However, you set up your Firebase security rules and other server side protection to secure your data. See Firebase security checklist for more information.

@russellwheatley great thanks; I hope we can implement live environmental switching; Having the recompile the app is either not an option (for QA teams) or a tremendous waste of time.

@acoutts I'm running a copy script, basically, the same as I do with GoogleService-Info.plist. Can you tell me where in the build Phases you run this script? It seems that it's not there when Crashlytics script starts running.

@loolooii my phases look like this in terms of ordering including my crashlytics one

@acoutts thanks man! It seems you do the copying way earlier, that must have been it. I ended up removing Crashlytics completely, it's nice and all, but I'll wait for it to be supported in the "new way". If not, I will try to do it again some time later. I needed success yesterday 😄

any update to configure the flavors using the cli directly?

Let me see if we are in the same page.
If I have a white label app, thst turns out to be 2 different apps in production, with 2 different Android ids, I will have to run the CLI once for each of my Android apps, and the last time I run the CLI, it won't interfere with the previous times I have run it, and configured the other Android apps?

Just to note; many of us switch on the login screen via a few different environments; real time. having to use different builds is very painful for QA.

Hey folks, we're looking to update the CLI to help users who require multiple environment setup. The biggest concern for us, regards the different approaches to setting up build types/flavors/schemes. We don't want to make assumptions about your particular setup. We propose exposing 3 new options which allow you to choose where to write the service file (“Google-Service-Info.plist” for iOS/macOS & “google-services.json” for Android). So for instance, you could write:
flutterfire config \
  --project=mycoolproject-dev \
  --out=lib/firebase_options_dev.dart \
  --ios-bundle-id=com.codewithandrea.flutterfire-flavors.dev \
  --macos-bundle-id=com.codewithandrea.flutterfire-flavors.dev \
  --android-app-id=com.codewithandrea.flutterfire-flavors.dev \
  --ios-out=/ios/directory/Google-Service-Info.plist \
  --android-out=/android/directory/google-services.json \
  --macos-out=/macos/directory/Google-Service-Info.plist \

The most important option would be that this tool does not write the service files at all and most importantly does not access my Firebase projects in the cloud in any way (for security reasons). I am developing my app actively and publishing updates almost monthly. I have updated the service files total of two times during the lifetime of my app and the last time I updated them was in June 2019. So it really is not a problem to download and update those files manually when needed as I have already done last 3 years. I don't have anything against automation, but in my opinion this is not a place where automation is really needed especially because it only causes security concerns. Well, I don't know if this tool can do anything useful if it cannot access the Firebase projects in cloud, but that's why I suggested to Add documentation how to use FlutterFire packages the old way without this tool (and keep the documentation up to date) which is still my preferred option.

Let me see if we are in the same page.

If I have a white label app, that turns out to be 2 different apps in production, with 2 different Android ids, I will have to run >the CLI once for each of my Android apps, and the last time I run the CLI, it won't interfere with the previous times I have >run it, and configured the other Android apps?

I want to be sure running the CLI multiple times, for different Android apps, won't mess up any previous configuration of other apps, since I have 3 android and 3 ios apps, generated from the same source code, just changing the app's IDs, names and icons.

Hey @feinstein, the idea is that it will grab the config from the Firebase Server and write to where ever you want it in your project setup with whatever file name you choose. They are independent file writes and won't interfere with each other. The setup part depends on how you've set it up. Firebase has its recommended way of setup for android flavors, not sure how else to set it up other than that method if that answers your question.

Do we still need the Google-Service-Info.plist and google-services.json file when we have the firebase_options_dev.dart?

Hey @erf, The service file is used before dart is initialized on native apps, therefore, the Dart config initialization code is ignored as default app has already been setup. We were thinking of removing android, iOS & macOS dart initialisation code from flutterfire configure, but some users use it for second app initialization as you can change certain aspects like RTDB & Auth URL to a different address in your Firebase project.

Hey @kinex, you can find manual installation here. You don't have to use flutterfire configure.

We wanted to move towards dart initialization, @erf. But there are too many unforeseen issues. Ultimately, we don't control how each Firebase product uses the service file, and it appears they are needed in certain circumstances.

Hey @kinex, you can find manual installation here. You don't have to use flutterfire configure.

The website has lots of warnings at the top, saying the content is not guaranteed to be updated and the manual configuration is not recommended, so when I read this, I get full of FUD that my project will be unstable.

In general I think this solution should be satisfactory, if we are controlling the folders where the CLI downloads, it would be practically the same as a manual installation.

Would be nice if the tooling was automatic; why aren’t we using api keys? Like every other 3rd tool that requires identification, instead of these ridiculous service accounts on the client?
All mobile developers are forced to use firebase since google scrapped GCM (shame on them) so let’s make it streamline as possible 😎

Did the firebase android and ios team have anything to say about some possible updates on their side to allow a dart only implementation ? I feel like this should be the first place to start.

I think this is getting out of the original topic, this thread won't solve the firebase architecture, or the Dart implementation, please open a new issue to discuss it.
Here we should stick to how to deal with flavors with the new CLI tool.

The manual installation is nothing specific to a Flutter app. It is essentially what Firebase specify when you create a native app on the Firebase console:

@erf No, it won't be removed. As mentioned earlier:

We were thinking of removing android, iOS & macOS dart initialisation code from flutterfire configure, but some users use it for second app initialization as you can change certain aspects like RTDB & Auth URL to a different address in your Firebase project.

It is also still used for initializing your web app.

@russellwheatley but will the Dart initialization work if I do the manual installation?
The manual installation is what's required on the native side, but we have no idea how this will interact with the new modifications in the Dart library, where a lot of things have been abstracted. The docs warnings don't help to ease our doubts.

I think this is getting out of the original topic, this thread won't solve the firebase architecture, or the Dart implementation, please open a new issue to discuss it.
Here we should stick to how to deal with flavors with the new CLI tool.

The build flavors are a waste of time for QA though and extremely annoying when doing team management, you have to keep a track of build numbers and if they are dev/prod/staging/testing etc etc, backwards.
I just want a function like
await Firebase.switchAccount("some-api-key")
and not care about anything else.

I think this is getting out of the original topic, this thread won't solve the firebase architecture, or the Dart implementation, please open a new issue to discuss it.
Here we should stick to how to deal with flavors with the new CLI tool.

The build flavors are a waste of time for QA though and extremely annoying when doing team management, you have to keep a track of build numbers and if they are dev/prod/staging/testing etc etc, backwards.
I just want a function like
await Firebase.switchAccount("some-api-key")
and not care about anything else.

That's your reality, for your project, and your company. Don't think this applies to everyone.
My company is a very big bank, and we have many partners, so we HAVE to create new apps, with new ids, one for each partner.
Since we only change the ids, names, icons and colors, we don't bother with QA for the other flavors, since the main code is always validated in the main app.

If you want a new functionality, please file a new issue, this is getting out of topic.

@russellwheatley maybe we should start closing off-topic comments to keep the focus on the main issue?

We have something like this, broken on Android but functioning on iOS.
initPushNotifs() async {
  if (isPushNotificationsSupported() && Firebase.apps.isEmpty) {
    try {
      if (EnvironementProvider.isProd()) {
        await Firebase.initializeApp(
          options: ProdFirebaseOptions.currentPlatform,
        );
      } else {
        await Firebase.initializeApp(
          options: DevFirebaseOptions.currentPlatform,
        );
      }
      _initPushNotifications();
    } catch (e) {
      if (kDebugMode) {
        print("Failed to init push notifs");
        print(e);
      }
    }
  } else {
    if (kDebugMode) {
      print("Already init Firebase. Need to restart app completely to refresh.");
    }
  }
}initPushNotifs() async {
  if (isPushNotificationsSupported() && Firebase.apps.isEmpty) {
    try {
      if (EnvironementProvider.isProd()) {
        await Firebase.initializeApp(
          options: ProdFirebaseOptions.currentPlatform,
        );
      } else {
        await Firebase.initializeApp(
          options: DevFirebaseOptions.currentPlatform,
        );
      }
      _initPushNotifications();
    } catch (e) {
      if (kDebugMode) {
        print("Failed to init push notifs");
        print(e);
      }
    }
  } else {
    if (kDebugMode) {
      print("Already init Firebase. Need to restart app completely to refresh.");
    }
  }
}

@feinstein The library is ridged and causing issues for developers, I can see that this issue has be logged many times looking over the issues in github.
Also using these service accounts is kinda silly in 2022 🤪 but I guess that's my opinion 🏄🏻♂

For android it does work like you said @sdstolworthy but for iOS the cli only outputs one file ios/firebase_app_id_file.json and it will overwrite it each time. We can manually fix it for iOS.
There is a warning printed when doing pod install:
Warning: firebase_app_id_file.json file does not exist. This may cause issues in upload-symbols. If this error is unexpected, try running flutterfire configure again.

I guess it can be ignored as long as you're sure you have set things up correctly.
What I did:

Ran the configure command multiple times, making sure to copy the ios/firebase_app_id_file.json file into my respective flavor folder each time. This is the same folder I store my GoogleService-Info.plist file for each flavor.

ios/Runner/Firebase/Prod/firebase_app_id_file.json
ios/Runner/Firebase/Sandbox/firebase_app_id_file.json

Added an xcode run script build phase which copies the correct firebase_app_id_file.json file into the root ios/ folder, just like the one for GoogleService-Info.plist works.

In my main.dart I use package_info_plus to know my package name to determine what flavor is running and configure firebase with the correct file accordingly:

import 'package:app/firebase_options_prod.dart';
import 'package:app/firebase_options_sandbox.dart';
import 'package:package_info_plus/package_info_plus.dart';

Future<void> main() async {
  late final PackageInfo packageInfo;
  try {
    packageInfo = await PackageInfo.fromPlatform();
  } catch (e, s) {
    /// Fallback value
    packageInfo = PackageInfo(
      appName: 'MyApp',
      packageName: 'com.myapp.prod',
      buildNumber: '0',
      version: '0.0.0',
    );
  }

  final isSandbox = packageInfo.packageName == 'com.myapp.sandbox';

  await Firebase.initializeApp(
  options: isSandbox
      ? firebase_sandbox.DefaultFirebaseOptions.currentPlatform
      : firebase_prod.DefaultFirebaseOptions.currentPlatform,
  );
}

Here is my run script I used:
# Name of the resource we're selectively copying
FIREBASE_APP_ID_FILE=firebase_app_id_file.json

# Get references to sandbox and prod versions of firebase_app_id_file.json
# NOTE: These should only live on the file system and should NOT be part of the target (since we'll be adding them to the target manually)
FIREBASE_APP_ID_FILE_SANDBOX=${PROJECT_DIR}/${TARGET_NAME}/Firebase/Sandbox/${FIREBASE_APP_ID_FILE}
FIREBASE_APP_ID_FILE_PROD=${PROJECT_DIR}/${TARGET_NAME}/Firebase/Prod/${FIREBASE_APP_ID_FILE}

# Make sure the sandbox version of firebase_app_id_file.json exists
echo "Looking for ${FIREBASE_APP_ID_FILE} in ${FIREBASE_APP_ID_FILE_SANDBOX}"
if [ ! -f $FIREBASE_APP_ID_FILE_SANDBOX ]
then
    echo "No sandbox firebase_app_id_file.json found. Please ensure it's in the proper directory."
    exit 1
fi

# Make sure the prod version of firebase_app_id_file.json exists
echo "Looking for ${FIREBASE_APP_ID_FILE} in ${FIREBASE_APP_ID_FILE_PROD}"
if [ ! -f $FIREBASE_APP_ID_FILE_PROD ]
then
    echo "No prod firebase_app_id_file.json found. Please ensure it's in the proper directory."
    exit 1
fi

# Get a reference to the destination location for firebase_app_id_file.json
FILE_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
echo "Will copy ${FIREBASE_APP_ID_FILE} to final destination: ${FILE_DESTINATION}"

# Copy over the correct firebase_app_id_file.json for the current build configuration
if [ "${CONFIGURATION}" == "Debug-prod" ] || [ "${CONFIGURATION}" == "Release-prod" ] || [ "${CONFIGURATION}" == "Profile-prod" ]
then
    echo "Using ${FIREBASE_APP_ID_FILE_PROD}"
    cp "${FIREBASE_APP_ID_FILE_PROD}" "${FILE_DESTINATION}"
elif [ "${CONFIGURATION}" == "Debug-sandbox" ] || [ "${CONFIGURATION}" == "Release-sandbox" ] || [ "${CONFIGURATION}" == "Profile-sandbox" ]
then
    echo "Using ${FIREBASE_APP_ID_FILE_SANDBOX}"
    cp "${FIREBASE_APP_ID_FILE_SANDBOX}" "${FILE_DESTINATION}"
else
    echo "Error: invalid configuration specified: ${CONFIGURATION}"
fi

At build/run time, it all works as expected because there's only one ios/firebase_app_id_file.json file and it's in the correct spot at build time thanks to the run script. Depending which flavor I select, it copies the right one into place just like it does for the GoogleService-Info.plist file.
This is a tough thing to solve in the cli tool because flavors are by design such a flexibly-implemented thing - people use all sorts of different approaches. I think there might just need to be a good doc page outlining the approach for setting it up for flavors and it's up to the user to adapt it to their specific implementation.

this would be a better script:
environment="default"

# Regex to extract the scheme name from the Build Configuration
# We have named our Build Configurations as Debug-dev, Debug-prod etc.
# Here, dev and prod are the scheme names. This kind of naming is required by Flutter for flavors to work.
# We are using the $CONFIGURATION variable available in the XCode build environment to extract
# the environment (or flavor)
# For eg.
# If CONFIGURATION="Debug-prod", then environment will get set to "prod".
if [[ $CONFIGURATION =~ -([^-]*)$ ]]; then
environment=${BASH_REMATCH[1]}
fi

echo $environment

# Name and path of the resource we're copying
FIREBASE_APP_ID_JSON=firebase_app_id_file.json
FIREBASE_APP_ID_FILE=${PROJECT_DIR}/Config/${environment}/${FIREBASE_APP_ID_JSON}

GOOGLESERVICE_INFO_PLIST=GoogleService-Info.plist
GOOGLESERVICE_INFO_FILE=${PROJECT_DIR}/Config/${environment}/${GOOGLESERVICE_INFO_PLIST}

# Make sure GoogleService-Info.plist exists
echo "Looking for ${GOOGLESERVICE_INFO_PLIST} in ${GOOGLESERVICE_INFO_FILE}"
if [ ! -f $GOOGLESERVICE_INFO_FILE ]
then
echo "No GoogleService-Info.plist found. Please ensure it's in the proper directory."
exit 1
fi

# Make sure firebase_app_id_file.json exists
echo "Looking for ${FIREBASE_APP_ID_JSON} in ${FIREBASE_APP_ID_FILE}"
if [ ! -f $FIREBASE_APP_ID_FILE ]
then
echo "No firebase_app_id_file.json found. Please ensure it's in the proper directory."
exit 1
fi

FIREBASE_PLIST_JSON_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
# Get a reference to the destination location for the GoogleService-Info.plist
# This is the default location where Firebase init code expects to find GoogleServices-Info.plist file
echo "Will copy ${GOOGLESERVICE_INFO_PLIST} to final destination: ${FIREBASE_PLIST_JSON_DESTINATION}"

# Get a reference to the destination location for the firebase_app_id_file.json
# This is the default location where Firebase init code expects to find firebase_app_id_file.json file
echo "Will copy ${FIREBASE_APP_ID_JSON} to final destination: ${FIREBASE_PLIST_JSON_DESTINATION}"

# Copy over the prod GoogleService-Info.plist for Release builds
cp "${GOOGLESERVICE_INFO_FILE}" "${FIREBASE_PLIST_JSON_DESTINATION}"

# Copy over the prod firebase_app_id_file.json for Release builds
cp "${FIREBASE_APP_ID_FILE}" "${FIREBASE_PLIST_JSON_DESTINATION}"

@WalidChebaro
May I know which was the order you use when running the script in your build phase configuration? There's any reference on how to add this script to the build phase?
Thank you 👍

@LutfiGarzon

Create a new run script phase name it:

Copy GoogleServices-Info.plist & firebase_app_id_file.json to the correct location

Replace the shell script with:

environment="default"

# Regex to extract the scheme name from the Build Configuration
# We have named our Build Configurations as Debug-dev, Debug-prod etc.
# Here, dev and prod are the scheme names. This kind of naming is required by Flutter for flavors to work.
# We are using the $CONFIGURATION variable available in the XCode build environment to extract
# the environment (or flavor)
# For eg.
# If CONFIGURATION="Debug-prod", then environment will get set to "prod".
if [[ $CONFIGURATION =~ -([^-]*)$ ]]; then
environment=${BASH_REMATCH[1]}
fi

echo $environment

# Name and path of the resource we're copying
FIREBASE_APP_ID_JSON=firebase_app_id_file.json
FIREBASE_APP_ID_FILE=${PROJECT_DIR}/Config/${environment}/${FIREBASE_APP_ID_JSON}

GOOGLESERVICE_INFO_PLIST=GoogleService-Info.plist
GOOGLESERVICE_INFO_FILE=${PROJECT_DIR}/Config/${environment}/${GOOGLESERVICE_INFO_PLIST}

# Make sure GoogleService-Info.plist exists
echo "Looking for ${GOOGLESERVICE_INFO_PLIST} in ${GOOGLESERVICE_INFO_FILE}"
if [ ! -f $GOOGLESERVICE_INFO_FILE ]
then
echo "No GoogleService-Info.plist found. Please ensure it's in the proper directory."
exit 1
fi

# Make sure firebase_app_id_file.json exists
echo "Looking for ${FIREBASE_APP_ID_JSON} in ${FIREBASE_APP_ID_FILE}"
if [ ! -f $FIREBASE_APP_ID_FILE ]
then
echo "No firebase_app_id_file.json found. Please ensure it's in the proper directory."
exit 1
fi

FIREBASE_PLIST_JSON_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
# Get a reference to the destination location for the GoogleService-Info.plist
# This is the default location where Firebase init code expects to find GoogleServices-Info.plist file
echo "Will copy ${GOOGLESERVICE_INFO_PLIST} to final destination: ${FIREBASE_PLIST_JSON_DESTINATION}"

# Get a reference to the destination location for the firebase_app_id_file.json
# This is the default location where Firebase init code expects to find firebase_app_id_file.json file
echo "Will copy ${FIREBASE_APP_ID_JSON} to final destination: ${FIREBASE_PLIST_JSON_DESTINATION}"

# Copy over the prod GoogleService-Info.plist for Release builds
cp "${GOOGLESERVICE_INFO_FILE}" "${FIREBASE_PLIST_JSON_DESTINATION}"

# Copy over the prod firebase_app_id_file.json for Release builds
cp "${FIREBASE_APP_ID_FILE}" "${FIREBASE_PLIST_JSON_DESTINATION}"

Then place it under:

Link Binary With Libraries

@russellwheatley If both the service file and the Dart initialization is active at the same time, which one will take precedence? Is there documentation describing these scenarios?

They are one and the same, if you initialize manually via native services files then when you call initializeApp() in Dart it syncs all natively created Firebase apps to Dart, and vice versa if you initialize purely via Dart then Dart calls native apis and creates the Firebase app instances there. You can even mix and match, initialize some via native and some via Dart (as long as Firebase app names are unique) - the act of calling initializeApp() in Dart is what synchronizes them which is why that method is documented as a required step to initialize Firebase for Flutter. The 'Firebase apps' available in Dart are always just a mirror of whats been created natively.
The problem of 'just doing it via Dart only' is that some Firebase services and features on Android/iOS do the following:

a) use these Firebase services plist/json files at application build time (native tooling build time, not Dart), e.g. Crashlytics uploading symbols for your build to support stacktrace deobfuscation
b) use these Firebase services plist/json files to interact with Firebase backend infra when Dart is not yet available (app startup, or background services), e.g. FCM , Analytics, Perf Mon and so on.

In both these scenarios Dart is not available yet and initializing Firebase via Dart would be too late. There's also fundamental architectural reasons for why these services behave like this that can't/won't be changed.

The goal of this CLI is to reduce friction when adopting the usage of Firebase in your project. Since initializing native Firebase SDKs via plist/json files is required and also that Dart only initialization for secondary Firebase apps (and default apps for Web) is a valid use case for Dart initialization then the CLI must do both.
Admittedly this causes friction for those using multiple environments and we're looking to address that with the new flags @russellwheatley mentioned above. I would note though that using the CLI is not a requirement, if you've already been doing multiple environments for your plist/json files manually then you can keep doing that, the CLI is not required - as long as you call  initializeApp() in Dart (which is mandatory anyway) to trigger the native -> Dart synchronization mechanism.

@russellwheatley but will the Dart initialization work if I do the manual installation?

@feinstein - yes, as above

@WalidChebaro Thank you works as expected great idea make initialization in iOS easy and seamless.

Hey folks, a quick update. We've cut a dev release for FFCLI which you can use and provide feedback here:
Activate dev release:
dart pub global activate flutterfire_cli 0.3.0-dev.13 --overwrite

You can find more details in the PR description here: https://github.com/invertase/flutterfire_cli/pull/132
But to summarise what this dev release does:

Created 3 new options which are macos-out, android-out & ios-out. They are paths to where you want your service file to be written in your Flutter project. You can name the service file whatever you want (e.g. ios/some/folder/servicefile.plist), but if you decide you want to add it to a particular scheme or target, it will ask if you want to rename to GoogleService-Info.plist which is necessary for Firebase to pick it up on initialisation. This means you will have to create separate folders to hold the service file (e.g. ios/production/GoogleService-Info.plist) when using scheme configuration.
For iOS/macOS, you will have a command prompt which allows you to select the target or scheme you wish to add the service file to. There is a third option that allows you to simply write the file to whatever directory you wish although you will have to ensure it is added to your app bundle yourself.
Another command prompt  allows you to add an upload debug symbol script for whatever target/scheme you wish for iOS/macOS. If you do decide to add the script, please delete the firebase_app_id.json file because it will be no longer needed, and it will upload debug symbols for whatever app id is contained within firebase_app_id.json which maybe incorrect if you have different flavors/schemes configured. To see what that file is doing, it is used here to grab the app id for uploading debug symbols for crashlytics.
Android is straight forward, you just get the option to write to a particular directory. If you follow Firebase's documentation, you just need to write the service file to the correct directory to setup different environments.

Example:
flutterfire configure  --ios-out=/ios/another/GoogleSerffmfmf-Info.plist \
  --android-out=/android/app/src/google-services.json --macos-out=/macos/another/GoogleService-Info.plist

Notes

If you do not specify a path, the CLI will just revert to existing behaviour for each platform.
At the moment, macOS iOS "scheme" setup will not work as there is a code signing issue. If you do setup macOS, use the target. We will try and fix this in a later release.
There are no command line flags to negate the new command line prompts, this will be updated in a later release.

If you do test it, could you update this channel with your findings or any issues. This will be really beneficial for helping us improve it for wider use. Thanks!

Could you add a User-Defined build settings (e.g. REVERSE_CLIENT_ID) for each scheme that contains the reverse client id?
I need to set it in Info.plist for google sign in.

Hey folks, a quick update. We've cut a dev release for FFCLI which you can use and provide feedback here:
Activate dev release:
dart pub global activate flutterfire_cli 0.3.0-dev.13 --overwrite

You can find more details in the PR description here: #132
But to summarise what this dev release does:

Created 3 new command line options which are macos-out, android-out & ios-out. They are paths to where you want your service file to be written in your Flutter project. You can name the service file whatever you want (e.g. ios/some/folder/servicefile.plist).
As mentioned above, for iOS/macOS, you will have a command prompt which allows you to select the target or scheme you wish to add the service file to. There is a third option that allows you to simply write the file to whatever directory you wish although you will have to ensure it is added to your app bundle yourself. if you decide you want to add it to a particular scheme or target, the CLI will prompt you if you want to rename your file GoogleService-Info.plist which is necessary for Firebase to pick it up on initialisation. This also means you will have to create separate folders to hold the service file (e.g. ios/production/GoogleService-Info.plist) when using scheme configuration.
Another command prompt  allows you to add a Crashlytics upload debug symbol script for whatever target/scheme you wish for iOS/macOS. If you do decide to add the script, please delete the firebase_app_id.json file because it will be no longer needed, and it will upload debug symbols for whatever app id is contained within firebase_app_id.json which maybe incorrect if you have different flavors/schemes configured. To see what that file is doing, it is used here to grab the app id for uploading debug symbols for Crashlytics.
Android is straight forward, you just get the option to write to a particular directory. If you follow Firebase's documentation, you just need to write the service file to the correct directory to setup different environments.

Example:
flutterfire configure  --ios-out=/ios/another/GoogleSerffmfmf-Info.plist \
  --android-out=/android/app/src/google-services.json --macos-out=/macos/another/GoogleService-Info.plist

Notes

If you do not specify a path, the CLI will just revert to existing behaviour for each platform.
At the moment, macOS iOS "scheme" setup will not work as there is a code signing issue. If you do setup macOS, use the target. We will try and fix this in a later release.
There are no command line flags to negate the new command line prompts, this will be updated in a later release.

If you do test it, could you update this channel with your findings or any issues. This will be really beneficial for helping us improve it for wider use. Thanks!

I followed these instructions to add three environments development/staging/production.  Now I need to add Firebase analytics and crashlytics to each environment.  What should I do?

Could you add a User-Defined build settings (e.g. REVERSE_CLIENT_ID) for each scheme so it contains the reverse client id?
I need to set it in Info.plist for google sign in.

You should be fine simply adding multiple reversed client IDs in the URL schemes. @agonhajdari

When i am using this command flutterfire configure --ios-out=/ios/prod/GoogleService-Info.plist
I am getting this error while generating build
`Error (Xcode): Build input file cannot be found: '/Users/krishnateja/Code/Pietech/hlp-app/ios/Runner/GoogleService-Info.plist'. Did you forget to declare this file as an
output of a script phase or custom build rule which produces it?
Encountered error while archiving for device.`
@russellwheatley

When i am using this command flutterfire configure --ios-out=/ios/prod/GoogleService-Info.plist
I am getting this error while generating build
`Error (Xcode): Build input file cannot be found: '/Users/krishnateja/Code/Pietech/hlp-app/ios/Runner/GoogleService-Info.plist'. Did you forget to declare this file as an output of a script phase or custom build rule which produces it?
Encountered error while archiving for device.`
@russellwheatley

My bad, I forgot to manually link the references in Xcode

Hey folks, a quick update. We've cut a dev release for FFCLI which you can use and provide feedback here:
Activate dev release:
dart pub global activate flutterfire_cli 0.3.0-dev.13 --overwrite

You can find more details in the PR description here: #132
But to summarise what this dev release does:

Created 3 new command line options which are macos-out, android-out & ios-out. They are paths to where you want your service file to be written in your Flutter project. You can name the service file whatever you want (e.g. ios/some/folder/servicefile.plist).
As mentioned above, for iOS/macOS, you will have a command prompt which allows you to select the target or scheme you wish to add the service file to. There is a third option that allows you to simply write the file to whatever directory you wish although you will have to ensure it is added to your app bundle yourself. if you decide you want to add it to a particular scheme or target, the CLI will prompt you if you want to rename your file GoogleService-Info.plist which is necessary for Firebase to pick it up on initialisation. This also means you will have to create separate folders to hold the service file (e.g. ios/production/GoogleService-Info.plist) when using scheme configuration.
Another command prompt  allows you to add a Crashlytics upload debug symbol script for whatever target/scheme you wish for iOS/macOS. If you do decide to add the script, please delete the firebase_app_id.json file because it will be no longer needed, and it will upload debug symbols for whatever app id is contained within firebase_app_id.json which maybe incorrect if you have different flavors/schemes configured. To see what that file is doing, it is used here to grab the app id for uploading debug symbols for Crashlytics.
Android is straight forward, you just get the option to write to a particular directory. If you follow Firebase's documentation, you just need to write the service file to the correct directory to setup different environments.

Example:
flutterfire configure  --ios-out=/ios/another/GoogleSerffmfmf-Info.plist \
  --android-out=/android/app/src/google-services.json --macos-out=/macos/another/GoogleService-Info.plist

Notes

If you do not specify a path, the CLI will just revert to existing behaviour for each platform.
At the moment, macOS iOS "scheme" setup will not work as there is a code signing issue. If you do setup macOS, use the target. We will try and fix this in a later release.
There are no command line flags to negate the new command line prompts, this will be updated in a later release.

If you do test it, could you update this channel with your findings or any issues. This will be really beneficial for helping us improve it for wider use. Thanks!

Hi thank you for this great improvement! It was a nightmare to manage flavors manually ^^)
Just wondering and I don't know if it's related but on registering Crashlytics I see that the if for bash script is wrong need double [[ instead on only one [

Hey @stact, thanks for bringing this to my attention. This will be fixed in the next dev release 👍

Hey folks, we've cut another dev release which should make things easier to run flutterfire configure multiple times. All the details can be found in the PR description here. To update to the latest dev release, please run:
dart pub global activate flutterfire_cli 0.3.0-dev.14 --overwrite

Even if you have no use for the additional command line arguments, it's worth updating for the fix to the bash scripts brought to my attention by @stact 🙏.
@ablbol This update should help you when you need to run flutterfire configure again. For example, when you've added Crashlytics to your project.
Once again, please let me know if you find any issues or ways to improve its function. Thanks.

Some issues i found. I was able to workaround these. @russellwheatley

On Linux and Mac GoogleService-Info.plist file were not generated, i added it manually to --ios-out folder.
On Linux no errors or warnings were shown when project.pbxproj was not updated.
On Mac project.pbxproj scripts were added, but there was as GOOGLESERVICE_INFO_PATH path issue, had to change:
from GOOGLESERVICE_INFO_PATH=${GOOGLESERVICE_INFO_PATH}/ios/Firebase/GoogleService-Info.plist
to GOOGLESERVICE_INFO_PATH=${GOOGLESERVICE_INFO_PATH}/ios/Firebase/development/GoogleService-Info.plist

flutterfire configure
--overwrite-firebase-options
--project=myapp-development
--out=lib/config/firebase/firebase_options_dev.dart
--ios-bundle-id=com.myapp.myapp.dev
--android-package-name=com.myapp.myapp.dev
--android-out=android/app/src/development
--ios-out=ios/Firebase/development
--ios-scheme=development
--debug-symbols-ios
--yes

For me the path on windows had to be set up differently, I thought I posted my findings here but I might have forgotten.
It would also be nice to be able to set the app name when registering the app, so it's  displayed accordingly in the firebase GUI

@russellwheatley this command
flutterfire configure --ios-scheme=development --ios-out=ios/dev/GoogleService-Info.plist --debug-symbols-ios --debug-symbols-macos  --macos-target=Runner --no-overwrite-firebase-options --yes --project=firebase-project

did not output a GoogleService-Info.plist inside ios/dev/ - I'm not sure how this all is suppose to work ? I'm using VGV flavors in my project & I'd like to use 3 different Firebase projects, one for each of my 3 flavors.
Would love some insights since it's not clear how those new changes are helping ? 🙂

Hey folks, thanks for the feedback! I'm working on a significant refactor here, and I will update this channel with an update on the changes I've made. I will also address the bugs mentioned by @AristideVB & @asaarnak 🙏

Depending on if some assumptions can be made when there are flavors, flutterfire configure:flavor dev might be a nice addition.
I suppose the following assumptions can be made:

a new firebase project needs to be picked
a new application name (for firebase) needs to be picked by could default to appName-flavor (eg: myapp-dev)
the service file can go in the corresponding android / subfolder
the firebase_options.dart file should have flavors suffix: FirebaseOptionsDev and firebase_options_dev.dart

@russellwheatley Thank you for your efforts! One thing I noticed is that the https://github.com/invertase/flutterfire_cli/pull/132 PR doesn't work with spaces in a --ios-out= path. By the way, it would be cool to have the option to disable automatic build script generation if someone wants to use his/her own script.

@russellwheatley

yeah, I guess that should handle spaces in paths. Can fix that I think.

Yeah, I was able to fix this manually by escaping all the spaces in the path declaration inside of the script. Like this:
GOOGLESERVICE_INFO_PATH=${GOOGLESERVICE_INFO_PATH}/ios/Scheme\ Dependent\ Files/prod/GoogleService-Info.plist

Which script are you referring to exactly?

Oh sorry it's actually named Build Phases in Xcode. Currently, flutterfire config has the option to disable [firebase_crashlytics] upload debug symbols script for "XXX" scheme build phases generation with the --no-debug-symbols-ios argument but I can't find anything like this for [firebase_core] add Firebase configuration to "***" scheme build phases.

It will only generate that build phase script if you choose the "build configuration" setting. The crashlytics build phase script is optional as you may not use it in your project. The script for "build configuration" is essential as it bundles your service file with your app. If you don't want that build phase script inserting, I suggest just choosing the option "just write to file". This won't create the build phase script and you can write whatever build phase script you wish to bundle the service file.

@AlexandrLevin-SelfTable

@russellwheatley

yeah, I guess that should handle spaces in paths. Can fix that I think.

Yeah, I was able to fix this manually by escaping all the spaces in the path declaration inside of the script. Like this:
GOOGLESERVICE_INFO_PATH=${GOOGLESERVICE_INFO_PATH}/ios/Scheme\ Dependent\ Files/prod/GoogleService-Info.plist

Which script are you referring to exactly?

Oh sorry it's actually named Build Phases in Xcode. Currently, flutterfire config has the option to disable [firebase_crashlytics] upload debug symbols script for "XXX" scheme build phases generation with the --no-debug-symbols-ios argument but I can't find anything like this for [firebase_core] add Firebase configuration to "XXX" scheme build phases.

I don't believe the spaces in-between characters in paths is an issue now with the latest, pending release. At least I couldn't get it to fail 👍. Once the latest release is out, I'll update this channel and if you still encounter a build issue, just let me know. Thanks.

We've cut the latest dev release for FlutterFire CLI. The PR notes contain the changes that were made and the reasons behind the changes which you can find here. It also has a table with the commands I tested which should help illustrate how to use the CLI to get what you want.
To install this dev release, please run the following in your terminal:
 dart pub global activate flutterfire_cli 0.3.0-dev.15 --overwrite

As always, feedback is welcome. We'll be looking to improve the CLI over the interim and your feedback is helpful. Please report any issues/bugs in this channel and we'll look to get them resolved in future releases. Thanks.

You have to specify the file names when using --ios-out & --android-out. So, it would be ios/Firebase/development/GoogleService-Info.plist for example. Same for android. I felt it had to be specified in case people wanted a different name for the file (i.e. if they simply want to write the file without configuring with a target or build configuration). Let me know if that solves the problem 👍
As far as paths go, they need to be pulled in otherwise the executables (flutterfire & dart) are not on the PATH variable in the Xcode environment. They have to be included. That script is replaced every time flutterfire configure is called. Therefore, the path will be specific to the environment of the machine, if that makes sense. For example, if I cloned your repo and ran flutterfire configure, it would make the paths specific to my machine.
Perhaps there is a better way, maybe see if the same is possible as a script to be run in the bash script itself to keep absolute paths from entering the script 🤔

@asaarnak

Do we need to install flutterfire_cli to CI(Codemagic) to run hidden commands bundle-service-file and upload-crashlytics-symbols?

You wouldn't be able run any FFCLI commands without it being installed if I understood your question correctly. (e.g. flutterfire configure). So yes, if you require FFCLI to run on your CI, it will have to be installed.

You have to specify the file names when using --ios-out & --android-out. So, it would be ios/Firebase/development/GoogleService-Info.plist for example. Same for android. I felt it had to be specified in case people wanted a different name for the file (i.e. if they simply want to write the file without configuring with a target or build configuration). Let me know if that solves the problem 👍

Assuming this is the problem, it could be an improvement to prompt the user to specify a file name if none is given.

Rerun same command with filenames.

Files are created in development folder but in firebase.json the serviceFileOutput is still old value without development folder. "serviceFileOutput":"ios/Firebase/GoogleService-Info.plist" deleting firebase.json and rerunning command fixed this.

--android-out=/android/app/src/development/google-services.json
--ios-out=/ios/Firebase/development/GoogleService-Info.plist

Fails when running without absolute urls(/ios/ and /android/ vs ios/ and android).
FileSystemException: Creation failed, path = '/Users/asaarnak/my-appandroid/app/src/development' (OS Error: Not a directory, errno = 20)

--android-out=android/app/src/development/google-services.json
--ios-out=ios/Firebase/development/GoogleService-Info.plist

@russellwheatley

You wouldn't be able run any FFCLI commands without it being installed if I understood your question correctly. (e.g. flutterfire configure). If you require FFCLI to run on your CI, it will have to be installed.

What command will copy ios/Firebase/development/GoogleService-Info.plist to ios/Runner/Info.plist folder.
We have staging and production builds in Codemagic.
Do we need to install FFCLI in Codemagic for copy script to work?

Rerun same command with filenames.

Files are created in development folder but in firebase.json the serviceFileOutput is still old value without development folder. "serviceFileOutput":"ios/Firebase/GoogleService-Info.plist" deleting firebase.json and rerunning command fixed this.

--android-out=/android/app/src/development/google-services.json
--ios-out=/ios/Firebase/development/GoogleService-Info.plist

Fails when running without absolute urls(/ios/ and /android/ vs ios/ and android).
FileSystemException: Creation failed, path = '/Users/asaarnak/my-appandroid/app/src/development' (OS Error: Not a directory, errno = 20)

--android-out=android/app/src/development/google-services.json
--ios-out=ios/Firebase/development/GoogleService-Info.plist

@asaarnak - thanks for the feedback. Appreciated. There's a lot of moving parts so it helps a lot.

The point about firebase.json might be a bug, I can look into that. I thought they'd be updated but perhaps not.
Yes, it is relative from your project. Absolute urls are not accepted. Perhaps we can implement future.
Not sure I'd recommend using it in a prod environment straight away 😅. But, you basically have to run this command in your CI environment setup (of course, need to install Flutter or Dart as well).

 dart pub global activate flutterfire_cli 0.3.0-dev.15 --overwrite

You will also need the firebase CLI itself for it to work which can be installed via node:
npm install -g firebase-tools

Not sure how this is achieved with CodeMagic, you would normally add it as a step in your workflow when using GitHub Actions. For example, here is how node is installed on the FlutterFire repo:
node setup
firebase CLI setup
We install Flutter which comes with the Dart SDK here
To install FlutterFire CLI, it'll be similar to how we're installing the Firebase CLI but using the command mentioned above.

That's a good point actually. I imagine you'll have to login first. Otherwise, it wouldn't know how to associate the CLI with your account.

Hey @stact, you will have to run the command for each environment you intend to use. VGV CLI creates an iOS app with 9 different build configurations. Choose the ones you want (presumably you don't need 9 different build configurations 😅) to use and run the command for each one.

I wrote a script that takes care of the firebase config of me. I hope this can be of some help.
NOTE: I am using very_google_cli for flutter to create the flutter project with flavors
download the script.dart file and copy it to your project dir.
Requirements:

Run dart pub add args in your project dir.
Install firebase CLI tools through npm using the command npm install -g firebase-tools. If you don't have node installed on your system please install it first.
Run this command dart pub global activate flutterfire_cli.

Steps:

If you have firebase CLI installed run firebase logout. We must logout from firebase in order for this process to work.
Login to firebase using firebase login. Don't use firebase login:ci, something the token is not registered using this method.
While standing in the project directory(./project/), and depending on the flavor for which you want to generate the firebase config run one of the following commands:

	dart run script.dart development
	dart run script.dart staging
	dart run script.dart production

The script will take care of generating firebase configs and copying them to their desired locations.
FOR IOS:
add a build phase and copy this IOS BUILD PHASE SCRIPT from this link and save it
This script will copy over the plist file and id.json file on app build.
screenshot

@drklrd56
Thanks for the script. it worked with android with a little bit of tuning.
But the IOS build phase script didn't.
I had to change the script into the below one for it to work
＊ I found it in one of the blogs
environment="default"

# Regex to extract the scheme name from the Build Configuration
# We have named our Build Configurations as Debug-dev, Debug-prod etc.
# Here, dev and prod are the scheme names. This kind of naming is required by Flutter for flavors to work.
# We are using the $CONFIGURATION variable available in the XCode build environment to extract
# the environment (or flavor)
# For eg.
# If CONFIGURATION="Debug-prod", then environment will get set to "prod".
if [[ $CONFIGURATION =~ -([^-]*)$ ]]; then
environment=${BASH_REMATCH[1]}
fi

echo $environment

# Name and path of the resource we're copying
GOOGLESERVICE_INFO_PLIST=GoogleService-Info.plist
GOOGLESERVICE_INFO_FILE=${PROJECT_DIR}/config/${environment}/${GOOGLESERVICE_INFO_PLIST}

# Make sure GoogleService-Info.plist exists
echo "Looking for ${GOOGLESERVICE_INFO_PLIST} in ${GOOGLESERVICE_INFO_FILE}"
if [ ! -f $GOOGLESERVICE_INFO_FILE ]
then
echo "No GoogleService-Info.plist found. Please ensure it's in the proper directory."
exit 1
fi

# Get a reference to the destination location for the GoogleService-Info.plist
# This is the default location where Firebase init code expects to find GoogleServices-Info.plist file
PLIST_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app
echo "Will copy ${GOOGLESERVICE_INFO_PLIST} to final destination: ${PLIST_DESTINATION}"

# Copy over the prod GoogleService-Info.plist for Release builds
cp "${GOOGLESERVICE_INFO_FILE}" "${PLIST_DESTINATION}"

@StephenBanz
You need to use the latest dev release 😄. Run:
 dart pub global activate flutterfire_cli 0.3.0-dev.15 --overwrite

@russellwheatley

You wouldn't be able run any FFCLI commands without it being installed if I understood your question correctly. (e.g. flutterfire configure). If you require FFCLI to run on your CI, it will have to be installed.

What command will copy ios/Firebase/development/GoogleService-Info.plist to ios/Runner/Info.plist folder. We have staging and production builds in Codemagic. Do we need to install FFCLI in Codemagic for copy script to work?

@asaarnak - thanks for the report on the firebase.json issue. I've just cut another dev release with a fix. Please run:
 dart pub global activate flutterfire_cli 0.3.0-dev.16 --overwrite

Tested that firebase.json is now updated when re-running flutterfire configure.
Does the bundle-service-file need firebase login? With flutterfire_cli 0.3.0-dev.14 the firebase login wasn't required.
The shellScript in project.pbxproj contains absolute path. Could this be converted to relative path?

running flutterfire_cli 0.3.0-dev.16, it keep asking The file name must be "GoogleService-Info.plist" if you're bundling with your iOS target or build configuration. Do you want to change filename to "GoogleService-Info.plist"?. is there an command line option to chose yes please?

The only time you can rename the file to something else on the CLI is if you're doing a simple write without any configuration (i.e. target or build configuration). It simply won't work if you have a different name for the file (it won't be recognised by Firebase iOS SDK when you bundle it with the app).
To be honest, it might be worth removing the ability to rename the file, and simply checking the filename matches GoogleService-Info.plist.
If the user makes the CLI choice to simply write the file and use their own service file bundling strategy, they're still going to have to name the file GoogleService-Info.plist. So it doesn't make sense that the file name should be anything but GoogleService-Info.plist 🤔.
I think I will change this in another dev release.

Tested that firebase.json is now updated when re-running flutterfire configure.
Does the bundle-service-file need firebase login? With flutterfire_cli 0.3.0-dev.14 the firebase login wasn't required.
The shellScript in project.pbxproj contains absolute path. Could this be converted to relative path?

On point 1, thanks for testing 🚀.
On point 2, I really don't think that is down to the FFCLI changes, we're doing nothing different that would constitute a firebase login.
On point 3, I think I will create a bash script that will get the paths on the fly without any need for relative/absolute paths. I think this is possible. If so, it will be in a future dev release.

Is it normal that the file firebase.json is responsible of the app GoogleService-Info.plist selection  ?
I've many flavors, if I didn't run flutterfire configure before run one of them, the firebase.json file is not reload and the app took the wrong GoogleService-Info..plist...

@EArminjon  My initial reaction is that you've associated the service file with a target. Do you have one or multiple targets? If you only have the default Runner target then it is always going to use the service file for the Runner target.
You should use "build configurations". Let me know how that goes. Thanks

@EArminjon My initial reaction is that you've associated the service file with a target. Do you have one or multiple targets? If you only have the default Runner target then it is always going to use the service file for the Runner target.
You should use "build configurations". Let me know how that goes. Thanks

I've 4 Targets : Runner, Notifications, Watch, Watch Extension.
I've 10 schemes : clienta, clientb, clientc,clientd etc.
I edit override my Targets properties with the current scheme.

I override my Targets properties with the current scheme.

Not quite sure what you mean by this. The CLI will bundle that service file with the target you select via command prompt/command line argument. It will be bundled with whatever target you choose to build.

Hey @stact, you will have to run the command for each environment you intend to use. VGV CLI creates an iOS app with 9 different build configurations. Choose the ones you want (presumably you don't need 9 different build configurations 😅) to use and run the command for each one.

@russellwheatley I was wondering if you could clarify this a little more -- I'm in the same boat, trying to add firebase to a project built w/ the vgv cli. It seems reasonable to me that you might want to have firebase work in all 9 build configurations, Debug/Profile/Release each for the dev/staging/prod flavors.
Assuming I do want to run flutterfire_configure 9 times, would each one need to specify a different GoogleService-Info.plist file via --ios-out? Or would I just run the command 3 times for each flavor, with
...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Debug-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Profile-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Release-development

etc.
With the examples I've seen here, it's not clear to me if that would work (I will try myself in the morning). I don't have a clear understanding of the platform specific build systems, so any info would be appreciated. Thanks!

Hey @stact, you will have to run the command for each environment you intend to use. VGV CLI creates an iOS app with 9 different build configurations. Choose the ones you want (presumably you don't need 9 different build configurations 😅) to use and run the command for each one.

@russellwheatley I was wondering if you could clarify this a little more -- I'm in the same boat, trying to add firebase to a project built w/ the vgv cli. It seems reasonable to me that you might want to have firebase work in all 9 build configurations, Debug/Profile/Release each for the dev/staging/prod flavors.
Assuming I do want to run flutterfire_configure 9 times, would each one need to specify a different GoogleService-Info.plist file via --ios-out? Or would I just run the command 3 times for each flavor, with
...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Debug-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Profile-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Release-development

etc.
With the examples I've seen here, it's not clear to me if that would work (I will try myself in the morning). I don't have a clear understanding of the platform specific build systems, so any info would be appreciated. Thanks!

Yes, you would have to run the command 9 times. Once for each build configuration. The firebase.json created at the root of the project contains the values for each build configuration required at build time for finding your service file to bundle and values required for uploading the debug symbols for Crashlytics.

Yes, you would have to run the command 9 times. Once for each build configuration. The firebase.json created at the root of the project contains the values for each build configuration required at build time for finding your service file to bundle and values required for uploading the debug symbols for Crashlytics.

Got it, thanks for clarifying!
@EArminjon thanks you! Very helpful

This is super helpful, thanks. However, is there a option to prevent it from adding the Crashlytics build step on iOS?

@EArminjon

This is super helpful, thanks. However, is there a option to prevent it from adding the Crashlytics build step on iOS?

With the echo, put no instead of yes. Note that, this will disable crashlytics steps inside the firebase.json too.

flutterfire_cli: ^0.3.0-dev.16
Build phases:

FlutterFire: "flutterfire upload-crashlytics-symbols"
FlutterFire: "flutterfire bundle-service-file"
-> using absolute path -> there will be problems when using it on another device

Currently:
PATH=${PATH}:/Applications/flutter/bin:/Users/xxx/.pub-cache/bin
Expected (MacOS)
PATH=${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin

@russellwheatley

flutterfire_cli: ^0.3.0-dev.16 Build phases:

FlutterFire: "flutterfire upload-crashlytics-symbols"
FlutterFire: "flutterfire bundle-service-file"
-> using absolute path -> there will be problems when using it on another device

Current: PATH=${PATH}:/Applications/flutter/bin:/Users/xxx/.pub-cache/bin Expect(MacOS): PATH=${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin

@bac-huuk - awesome, that should work I think, I'll get this updated as part of the changes I'm currently making 👍

Hey folks, I thought I'd get a quick temperature check on iOS/macOS configuration.
Is it useful making targets (i.e. --ios-target or --macos-target flags) configurable? It's quite a bit of work and adds a lot more complexity that might not be necessary if folks aren't using it.
I suspect the majority of people are going to build apps using build configurations (i.e. --ios-build-config or --macos-build-config flags). I was thinking of removing target configuration, but we will keep it if it is popular and being used.
I've created a survey monkey with a single question to find out if it is being used, and the results will determine whether we keep it. Please vote here: https://www.surveymonkey.co.uk/r/MVYWR78
Thanks!

Sorry, can you explain the difference? When we would use one or the other?

Little feedback, some developpers create flavors using multiple target instead of multiple build configuration. I think it could be good to keep this option for flexibility.
Btw, is it possible or allowed to select a target a and a specific build configuration? Actually, if I'm not wrong, the script only alllow target or only build configuration but didn't allow to mix them. This could be also great to increase flexibility of this tool...
But yep, it increase complexity.

@feinstein

Sorry, can you explain the difference? When we would use one or the other?

target - a standard Flutter app (flutter create some_app) created has a Runner target only. It does not come with multiple targets, you would have to set them up if you wanted different targets for different environments (e.g. development, staging, production).
build configuration - a standard Flutter app comes with three different build configurations set up: Debug, Profile & Release. You can see the build configurations by opening Xcode and editing the schemes:

The VGV CLI actually creates 9 different build configurations on your Xcode project, and one target. I believe most developers will go down the road of using build configurations hence why I think it might not be worth the effort for targets.

Thank you for the explanation. AFAIK Flutter can only work with build configurations, the Flutter tool only accepts a target named Runner.
My app has lots of different build configurations, since it's a white label app, so we need to combine the white label with the environment, and their combination become the build configurations.

I think build configurations are more than enough since offical Creating flavors for Flutter creates only build configurations.

Flavors (known as build configurations in iOS), allow you (the developer) to create separate environments for your app using the same code base.

https://docs.flutter.dev/deployment/flavors#creating-flavors-in-ios

Is the build script still mandatory to move google service info plist into the correct directory ?
I'm having
Build input file cannot be found: '/app/ios/Runner/GoogleService-Info.plist'. Did you forget to declare this file as an output of a script phase or custom build rule which produces it?
While the file generated have been put into /ios/dev/GoogleService-Info.plist,/ios/staging/GoogleService-Info.plist, ...

I'm just thinking out loud - shouldn't this issue be renamed to something that relates to both the Android and iOS platforms, to give it more meaning as it actually relates to not just iOS.

@davidnwaneri it only relates to iOS. Android does not have build configurations and the multi-environment setup for Android has not changed.

Sorry if a bit off topic, but i support multiple environments now quite easliy, without using flavors / multiple schemes, by using --dart-define-from-file, given an config_{my_env}.json file, and configuring this as part of my vscode launch.json. In the case of GoogleService-Info.plist and it's Android counterpart google-services.json, i use a vscode preLaunchTask to call a bash script which copies the correct Firebase config file to it's respective directory.
This inspired me to write an Medium article.

Sorry if a bit off topic, but i support multiple environments now quite easliy, without using flavors / multiple schemes, by using --dart-define-from-file, given an config_{my_env}.json file, and configuring this as part of my vscode launch.json. In the case of GoogleService-Info.plist and it's Android counterpart google-services.json, i use a vscode preLaunchTask to call a bash script which copies the correct Firebase config file to it's respective directory.
This inspired me to write an Medium article.

This is nice for some basic application, but how you want to support things like custom app icons, applicationIdSuffix, custom label per flavor etc? That is, any config on native side of application without using flavors / multiple schemes?

This is nice for some basic application, but how you want to support things like custom app icons, applicationIdSuffix, custom label per flavor etc? That is, any config on native side of application without using flavors / multiple schemes?

You would pass in those things as arguments via the config{_prod|dev}.json you pass in via --dart-define-from-file. You are able to access those variables natively (as mentioned in the article), on Android in build.gradle via project.getProperty, from there you can set various other properties (like applicationIdSuffix). And on iOS via Generated.xcconfig. E.g. you could store the app icons using different file names for different builds and pass the name you'd want to use for the current build as an argument via config.json or you could copy the file want to use as a preLaunchTask. I hope that give you some ideas. I'd rather not discuss this further here as to not make too much noise.

@erf
Thanks, the idea of using vs code to change the GoogleService-Info.plist, worked in my case while the build phase scripts with the latest version of the cli somehow always had issues. Note that I'm using flavors too.
What worked for me for ios and android:

Create flavors with flutter_flavorizr
Go back to stable version of the flutterfire cli
run flutterfire configure  for dev

flutterfire configure --project myproject-dev --platforms='web,ios,android' --out ../infrastructure/lib/firebase/configs/firebase_options_dev.dart --ios-bundle-id com.myproject.app.dev --android-package-name com.myproject.app.dev

Move google-service.json in the correct flavor directory in android
Move GoogleService-Info.plist and firebase_app_id_file.json under ios/Configs/dev/
Repeat step 3 to 5 for staging and prod
add tasks.json in .vscode

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "copy-config-dev-task",
      "type": "shell",
      "command": "cp app/ios/Configs/dev/firebase_app_id_file.json app/ios/firebase_app_id_file.json && cp app/ios/Configs/dev/GoogleService-Info.plist app/ios/Runner/GoogleService-Info.plist"
    },
    {
      "label": "copy-config-staging-task",
      "type": "shell",
      "command": "cp app/ios/Configs/staging/firebase_app_id_file.json app/ios/firebase_app_id_file.json && cp app/ios/Configs/staging/GoogleService-Info.plist app/ios/Runner/GoogleService-Info.plist"
    },

Add launcher preLaunchTask

  "configurations": [
    {
      "name": "myproject dev",
      "request": "launch",
      "type": "dart",
      "program": "app/lib/main_dev.dart",
      "preLaunchTask": "copy-config-dev-task",
      "args": [
        "--flavor",
        "dev",
      ]
    },
  ]

I have tested 0.3.0-dev.16 by running for each of the 9 build/flavor combos on latest flutter. This is using a new project created with very_good create flutter_app
Flutter 3.10.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 84a1e904f4 (6 days ago) • 2023-05-09 07:41:44 -0700
Engine • revision d44b5a94c9
Tools • Dart 3.0.0 • DevTools 2.23.1

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Debug-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Profile-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Release-development

I consistently get the following error:
Unable to find a target named `RunnerTests` in project `Runner.xcodeproj`, did find `Runner`.

I've tried 0.3.0-dev.16 and called the following command on my project my_app:
flutterfire configure \
<EMAIL_ADDRESS>\
  --project="my-firebase-dev" \
  --platforms="ios,android" \
  --ios-build-config=Debug-dev \
  --ios-out=ios/config/dev/GoogleService-Info.plist \
  --android-out=android/app/src/dev/google-services.json \
  --ios-bundle-id="com.company.myapp.dev" \
  --android-package-name="com.company.myapp.dev" \
  --debug-symbols-ios \
  --overwrite-firebase-options \
  --yes

There are still some issues:

The generated google-services.json was created in a wrong path, the first folder in the hierarchy was my_appandroid instead of android. So it generated a new folder my_appandroid. There could be something wrong with the path logic in the CLI. I could fix it by declaring --android-out=/android/app/src/dev/google-services.json with a / in front of android.
The CLI didn't overwrite the Google-Service plist as I expected because in this case, I wanted to register new apps with Firebase. Since you offered a --[no-]overwrite-firebase-options, wondering whether you should also offer an option to overwrite the plist file? Or was there a bug with the CLI? Right now, I worked around by deleting the plist file before running the configure command.
The generated shellScript for both flutterfire bundle-service-file action & flutterfire upload-crashlytics-symbol action still got some user-dependent path. For example:

#!/bin/bash
PATH=${PATH}:/Users/thuy/dev/flutter/bin:/Users/thuy/.pub-cache/bin
flutterfire bundle-service-file --plist-destination=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app --build-configuration=${CONFIGURATION} --platform=ios --apple-project-path=${SRCROOT}

The Users/thuy/dev/flutter/bin:/Users/thuy/.pub-cache/bin is rather my local path. This is a problem if working with a team project. Is it necessary to include PATH=${PATH}:/Users/thuy/dev/flutter/bin:/Users/thuy/.pub-cache/bin in the shell script? If one uses flutterfire, should it be already available in the local path as well as CI path, right?
Nonetheless, good to see that the CLI is getting more flexible and useful. Hope this helps.

The bundle-service-file script seems very broken:

Unhandled exception:
type 'Null' is not a subtype of type 'Map<dynamic, dynamic>' in type cast
#0      appleConfigFromFirebaseJson (package:flutterfire_cli/src/common/utils.dart:253:46)
<asynchronous suspension>
#1      BundleServiceFile.run (package:flutterfire_cli/src/commands/bundle_service_file.dart:86:9)
<asynchronous suspension>
#2      CommandRunner.runCommand (package:args/command_runner.dart:212:13)
<asynchronous suspension>
#3      main (file:///Users/thuy/.pub-cache/hosted/pub.dev/flutterfire_cli-0.3.0-dev.16/bin/flutterfire.dart:63:5)
<asynchronous suspension>
Command PhaseScriptExecution failed with a nonzero exit code

Command PhaseScriptExecution failed with a nonzero exit code

My project has a very typical multi-flavor setup with 2 schemes: dev and pro and 4 build configurations: Debug-dev, Profile-dev, Release-dev, Debug-pro, Profile-pro, and Release-pro.

Hey @thuytrinh, thanks for the feedback! There's been a lot of changes to the codebase since the last release: https://github.com/invertase/flutterfire_cli/pulls?q=is%3Apr+sort%3Aupdated-desc+is%3Amerged
I'll double check your observations before making another release. Thanks 👍

Thanks for your comments. For me firebase_app_id_file.json files are not being generated. I'm using @EArminjon super script but looks like something is wrong in 0.3.0-dev.16 version.
My project has 3 flavors and I was copying GoogleService-Info.plist with the Build Phase script on XCode. Is this script still necessary?
Problems came when I added analytics and crashlytics to my 3 environments.
In fact I don't know if I really need firebase_app_id_file.json files. I would appreciate a explanation of what this file is thought to. Looks like it duplicates GoogleService-Info.plist info.
Don't like the idea of changing GoogleService-Info.plist with VS Code tasks. It would work on our dev environment, but integrating the project with automated deployment services would be a headache.

@gelas7 - the pending dev release doesn't generate firebase_app_id_file.json file anymore, a script is created in the Run Phase Build Script's that will upload the symbols without this file being written to your codebase.

I've tried 0.3.0-dev.16 and called the following command on my project my_app:
flutterfire configure \
<EMAIL_ADDRESS>\
  --project="my-firebase-dev" \
  --platforms="ios,android" \
  --ios-build-config=Debug-dev \
  --ios-out=ios/config/dev/GoogleService-Info.plist \
  --android-out=android/app/src/dev/google-services.json \
  --ios-bundle-id="com.company.myapp.dev" \
  --android-package-name="com.company.myapp.dev" \
  --debug-symbols-ios \
  --overwrite-firebase-options \
  --yes

There are still some issues:

The generated google-services.json was created in a wrong path, the first folder in the hierarchy was my_appandroid instead of android. So it generated a new folder my_appandroid. There could be something wrong with the path logic in the CLI. I could fix it by declaring --android-out=/android/app/src/dev/google-services.json with a / in front of android.
The CLI didn't overwrite the Google-Service plist as I expected because in this case, I wanted to register new apps with Firebase. Since you offered a --[no-]overwrite-firebase-options, wondering whether you should also offer an option to overwrite the plist file? Or was there a bug with the CLI? Right now, I worked around by deleting the plist file before running the configure command.
The generated shellScript for both flutterfire bundle-service-file action & flutterfire upload-crashlytics-symbol action still got some user-dependent path. For example:

#!/bin/bash
PATH=${PATH}:/Users/thuy/dev/flutter/bin:/Users/thuy/.pub-cache/bin
flutterfire bundle-service-file --plist-destination=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app --build-configuration=${CONFIGURATION} --platform=ios --apple-project-path=${SRCROOT}

The Users/thuy/dev/flutter/bin:/Users/thuy/.pub-cache/bin is rather my local path. This is a problem if working with a team project. Is it necessary to include PATH=${PATH}:/Users/thuy/dev/flutter/bin:/Users/thuy/.pub-cache/bin in the shell script? If one uses flutterfire, should it be already available in the local path as well as CI path, right?
Nonetheless, good to see that the CLI is getting more flexible and useful. Hope this helps.

I checked all three issues you mentioned. None of them are an issue anymore:

Fixed in the refactor PR:
https://github.com/invertase/flutterfire_cli/pull/167
Fixed in this PR:
https://github.com/invertase/flutterfire_cli/pull/174
Fixed in this PR:
https://github.com/invertase/flutterfire_cli/pull/175

I am hoping to get another dev release out soon, just going through review process at the moment 👍

The bundle-service-file script seems very broken:

Unhandled exception:
type 'Null' is not a subtype of type 'Map<dynamic, dynamic>' in type cast
#0      appleConfigFromFirebaseJson (package:flutterfire_cli/src/common/utils.dart:253:46)
<asynchronous suspension>
#1      BundleServiceFile.run (package:flutterfire_cli/src/commands/bundle_service_file.dart:86:9)
<asynchronous suspension>
#2      CommandRunner.runCommand (package:args/command_runner.dart:212:13)
<asynchronous suspension>
#3      main (file:///Users/thuy/.pub-cache/hosted/pub.dev/flutterfire_cli-0.3.0-dev.16/bin/flutterfire.dart:63:5)
<asynchronous suspension>
Command PhaseScriptExecution failed with a nonzero exit code

Command PhaseScriptExecution failed with a nonzero exit code

My project has a very typical multi-flavor setup with 2 schemes: dev and pro and 4 build configurations: Debug-dev, Profile-dev, Release-dev, Debug-pro, Profile-pro, and Release-pro.

I haven't come across this yet, I wonder if you tried to edit the "firebase.json" file manually? If so, you shouldn't 😄

I have tested 0.3.0-dev.16 by running for each of the 9 build/flavor combos on latest flutter. This is using a new project created with very_good create flutter_app
Flutter 3.10.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 84a1e904f4 (6 days ago) • 2023-05-09 07:41:44 -0700
Engine • revision d44b5a94c9
Tools • Dart 3.0.0 • DevTools 2.23.1

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Debug-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Profile-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Release-development

I consistently get the following error:
Unable to find a target named `RunnerTests` in project `Runner.xcodeproj`, did find `Runner`.

This is bizarre, this feedback is from the CLI
> Unable to find a target named `RunnerTests` in project `Runner.xcodeproj`, did find `Runner`.

It is saying you selected RunnerTests as the target, but it could only find Runner as the target. show me the command you're running, please?

I have tested 0.3.0-dev.16 by running for each of the 9 build/flavor combos on latest flutter. This is using a new project created with very_good create flutter_app
Flutter 3.10.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 84a1e904f4 (6 days ago) • 2023-05-09 07:41:44 -0700
Engine • revision d44b5a94c9
Tools • Dart 3.0.0 • DevTools 2.23.1

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Debug-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Profile-development

...
--ios-out=/ios/Firebase/development/GoogleService-Info.plist \
--ios-build-config=Release-development

I consistently get the following error:
Unable to find a target named `RunnerTests` in project `Runner.xcodeproj`, did find `Runner`.

This is bizarre, this feedback is from the CLI
> Unable to find a target named `RunnerTests` in project `Runner.xcodeproj`, did find `Runner`.

It is saying you selected RunnerTests as the target, but it could only find Runner as the target. show me the command you're running, please?

Have the same issue on an empty project, I think it happens on the pod install step. Commented out in Podfile for now:
...
  #target 'RunnerTests' do
    #  inherit! :search_paths
  #end
...

Not an experienced mobile / flutter dev so no idea what I'm doing yet. FYI.

I've tried 0.3.0-dev.16 and called the following command on my project my_app:
flutterfire configure \
<EMAIL_ADDRESS>\
  --project="my-firebase-dev" \
  --platforms="ios,android" \
  --ios-build-config=Debug-dev \
  --ios-out=ios/config/dev/GoogleService-Info.plist \
  --android-out=android/app/src/dev/google-services.json \
  --ios-bundle-id="com.company.myapp.dev" \
  --android-package-name="com.company.myapp.dev" \
  --debug-symbols-ios \
  --overwrite-firebase-options \
  --yes

There are still some issues:

The generated google-services.json was created in a wrong path, the first folder in the hierarchy was my_appandroid instead of android. So it generated a new folder my_appandroid. There could be something wrong with the path logic in the CLI. I could fix it by declaring --android-out=/android/app/src/dev/google-services.json with a / in front of android.
The CLI didn't overwrite the Google-Service plist as I expected because in this case, I wanted to register new apps with Firebase. Since you offered a --[no-]overwrite-firebase-options, wondering whether you should also offer an option to overwrite the plist file? Or was there a bug with the CLI? Right now, I worked around by deleting the plist file before running the configure command.
The generated shellScript for both flutterfire bundle-service-file action & flutterfire upload-crashlytics-symbol action still got some user-dependent path. For example:

#!/bin/bash
PATH=${PATH}:/Users/thuy/dev/flutter/bin:/Users/thuy/.pub-cache/bin
flutterfire bundle-service-file --plist-destination=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app --build-configuration=${CONFIGURATION} --platform=ios --apple-project-path=${SRCROOT}

The Users/thuy/dev/flutter/bin:/Users/thuy/.pub-cache/bin is rather my local path. This is a problem if working with a team project. Is it necessary to include PATH=${PATH}:/Users/thuy/dev/flutter/bin:/Users/thuy/.pub-cache/bin in the shell script? If one uses flutterfire, should it be already available in the local path as well as CI path, right?
Nonetheless, good to see that the CLI is getting more flexible and useful. Hope this helps.

I checked all three issues you mentioned. None of them are an issue anymore:

Fixed in the refactor PR:
refactor: update implementation to make it more modular and easier to understand #167
Fixed in this PR:
feat: overwrite Apple service files if they exist already. #174
Fixed in this PR:
fix: remove absolute paths from run phase build script #175

I am hoping to get another dev release out soon, just going through review process at the moment 👍

Hi any update about the new release :) ?
(working on team project, the issue about local path is important)

As mentioned we don’t need 9 flavors to be set up
https://github.com/invertase/flutterfire_cli/issues/14#issuecomment-1423921383
Please also get additional details in whole conversation for how to check flavors https://github.com/invertase/flutterfire_cli/issues/14#issuecomment-1488254402
also be aware it’s in development not for prod purpose you can still configure and go live with manual configuration
hope it helps

I will update the channel when the latest dev release is out @EArminjon. I'm hoping not too long but it is going through a review process as a lot of changes have occurred since the last release.

So I come back to this thread every time I need to start a new project in Flutter hoping there's an official solution, but the recent comments got me a bit confused. Simple question:
As of July 2023, is FlutterFire Cli able to generate the right configuration for each platform, considering multiple Flavors associated with their respective Firebase projects, without neglecting that essential tools like Analytics and Crashlytics require unique google-services.json files in each environment?

@maRci002 I think so, yes. I have it working correctly, at least with Crashlytics (I haven't added Analytics). You have to run the command many times, once for each combination of build configuration (e.g. Debug, Release, Profile) and each flavor. So with the standard dev/staging/prod flavors you would run the command 9 times. I've modified a script that was shared above to do this in my projects, and I'm happy to post it if needed.

Any update?, I need some tutorial for this lol, the last messages are confusing, greetings! 👍

Thank you, @mxknt! Would you mind sharing your version?

X2 @mxknt  👍

@mavinis @Garciconx Sure thing, here's the first script that configures the build configurations for a single flavor:
./scripts/_configure_firebase_flavor.sh:
#!/bin/sh

if [ $# -ne 3 ]; then
 echo "Need 3 arguments: firebaseProjectID, flavor, bundleID"
 exit 1
fi

PROJECT=$1
FLAVOR=$2
BUNDLE_ID=$3
ACCOUNT=<your firebase account logged into the CLI>

CONFIG_DIR="lib/config/firebase"

for prefix in "Debug" "Release" "Profile"; do
 echo 'yes' | flutterfire configure \
   --account="$ACCOUNT" \
   --project="$PROJECT" \
   --out="$CONFIG_DIR"/"$FLAVOR"/firebase_options.dart \
   --android-out=/android/app/src/"$FLAVOR"/google-services.json \
   --ios-bundle-id="$BUNDLE_ID" \
   --android-package-name="$BUNDLE_ID" \
   --ios-out=/ios/Firebase/"$FLAVOR"/GoogleService-Info.plist \
   --ios-build-config="$prefix"-"$FLAVOR" \
   --yes
done

Then this script just calls the other one three times, once for each flavor:
#!/bin/sh

BUNDLE=<your app bundle id>

#you can replace the firebase projects and bundle suffixes as needed
./scripts/_configure_firebase_flavor.sh "<firebase-project>-prod" "production" "$BUNDLE"
./scripts/_configure_firebase_flavor.sh "<firebase-project>-staging" "staging" "$BUNDLE.stg"
./scripts/_configure_firebase_flavor.sh "<firebase-project>-dev" "development" "$BUNDLE.dev"

This will configure firebase for each flavor and build configuration, and put the firebase_options.dart file into lib/config/firebase/development, lib/config/firebase/staging etc.

@mxknt
Unhandled exception:
Could not find an option named "android-out" 🤔

@russellwheatley any idea? help 😢

@mavinis Did it work for you?

Thank you so much @gelas7 , I'm gonna try 👍

@mavinis @Garciconx Sure thing, here's the first script that configures the build configurations for a single flavor:
./scripts/_configure_firebase_flavor.sh:
#!/bin/sh

if [ $# -ne 3 ]; then
 echo "Need 3 arguments: firebaseProjectID, flavor, bundleID"
 exit 1
fi

PROJECT=$1
FLAVOR=$2
BUNDLE_ID=$3
ACCOUNT=<your firebase account logged into the CLI>

CONFIG_DIR="lib/config/firebase"

for prefix in "Debug" "Release" "Profile"; do
 echo 'yes' | flutterfire configure \
   --account="$ACCOUNT" \
   --project="$PROJECT" \
   --out="$CONFIG_DIR"/"$FLAVOR"/firebase_options.dart \
   --android-out=/android/app/src/"$FLAVOR"/google-services.json \
   --ios-bundle-id="$BUNDLE_ID" \
   --android-package-name="$BUNDLE_ID" \
   --ios-out=/ios/Firebase/"$FLAVOR"/GoogleService-Info.plist \
   --ios-build-config="$prefix"-"$FLAVOR" \
   --yes
done

Then this script just calls the other one three times, once for each flavor:
#!/bin/sh

BUNDLE=<your app bundle id>

#you can replace the firebase projects and bundle suffixes as needed
./scripts/_configure_firebase_flavor.sh "<firebase-project>-prod" "production" "$BUNDLE"
./scripts/_configure_firebase_flavor.sh "<firebase-project>-staging" "staging" "$BUNDLE.stg"
./scripts/_configure_firebase_flavor.sh "<firebase-project>-dev" "development" "$BUNDLE.dev"

This will configure firebase for each flavor and build configuration, and put the firebase_options.dart file into lib/config/firebase/development, lib/config/firebase/staging etc.

@russellwheatley What suggested by @mxknt is correct and works. The only thing is that at the end of flutterfire configure (considering the latest build 0.3.0dev16) there is always a single lib/firebase_options.dart that refers to the latest flutterfire_cli command launched in the terminal (or in the script).
What I suggest for the moment is to create two separate firebase_options.dart files, one for production and one for development (or even staging, by going classic), i.e. inside lib/ folder there have to be firebase_options-development.dart and firebase_options-production.dart (and firebase_options-staging.dart if this is the case), in which are defined the classes DefaultFirebaseOptionsDevelopment and DefaultFirebaseOptionsProduction, with the same structure of the firebase_options.dart, respectively.
Then, inside main.dart or where there is the "Firebase.initializeApp" give the correct configuration base on the current flavor. The easiest example could be the following:
  PackageInfo packageInfo = await PackageInfo.fromPlatform();
  String packageName = packageInfo.packageName;
  LoggerService().easy("___: PACKAGE NAME :___ $packageName");
  if(packageName.endsWith("dev")) {
    await Firebase.initializeApp(
      options: DefaultFirebaseOptionsDevelopment.currentPlatform, // <--- development configuration
    );
  } else {
    await Firebase.initializeApp(
      options: DefaultFirebaseOptionsProduction.currentPlatform, // <--- production configuration
    );
  }

Here I used the PackageInfo plugin from pub.dev to check the current package name and, if the name ends with dev for example, then the Development configuration will be loaded for Firebase, otherwise Production.
Hope it helps!
Thanks!

Using flutterfire 0.3.0-dev.16 and the above script from @mxknt I keep receiving the following error:
Unhandled exception:
    PathNotFoundException: Cannot open file, path = '/Users/Me/Developer/firebase.json' (OS Error: No such file or directory, errno = 2)

For some reason it won't recognize the firebase.json in the directory. I have been at it for a couple days and could use some insight. I've tried multiple fresh projects and different configures. It doesn't happen when using simple flutterfire configure.
flutterfire: 0.3.0-dev.16
flutter: 3.10.6
firebase_core: ^2.15.0
firebase_crashlytics: ^3.3.4

I used the flutterfire configure command manually, just to avoid that some errors could be related to flutterfire cli, when in reality they come from third party scripts. I just preferred to use the command on its own, in order to be focused only on the possible errors coming only from the cli.

I am using 0.3.0-dev.16 as well. I can build an iOS app from the command line level without problems. But when I try to build from Xcode I receive this:
/Users/toma/.pub-cache/bin/flutterfire: line 8: dart: command not found
Command PhaseScriptExecution failed with a nonzero exit code

flutterfire: 0.3.0-dev.16
flutter: 3.10.3
firebase_core: ^2.13.1
firebase_storage: ^11.2.2
firebase_auth: ^4.6.2
firebase_dynamic_links: ^5.3.2
firebase_crashlytics: ^3.3.2
firebase_messaging: ^14.6.2
firebase_analytics: ^10.4.2
firebase_remote_config: ^4.2.2
cloud_firestore: ^4.8.0
cloud_functions: ^4.3.2

Try to do a flutter clean before, then flutter pub get and follow the instructions outlined in the following README file:

I don't know why, but flutter fire script made my every build fail.
/Users/user/.pub-cache/bin/flutterfire:
#!/usr/bin/env sh
# This file was created by pub v3.1.0-edge.486b3b380e071d6770f8c6a9007e046af84cb888.
# Package: flutterfire_cli
# Version: 0.3.0-dev.16
# Executable: flutterfire
# Script: flutterfire
if [ -f /Users/toma/.pub-cache/global_packages/flutterfire_cli/bin/flutterfire.dart-3.1.0-edge.486b3b380e071d6770f8c6a9007e046af84cb888.snapshot ]; then
  dart "/Users/toma/.pub-cache/global_packages/flutterfire_cli/bin/flutterfire.dart-3.1.0-edge.486b3b380e071d6770f8c6a9007e046af84cb888.snapshot" "$@"
  # The VM exits with code 253 if the snapshot version is out-of-date.
  # If it is, we need to delete it and run "pub global" manually.
  exit_code=$?
  if [ $exit_code != 253 ]; then
    exit $exit_code
  fi
  dart pub global run flutterfire_cli:flutterfire "$@"
else
  dart pub global run flutterfire_cli:flutterfire "$@"
fi

Try to do a flutter clean before, then flutter pub get and follow the instructions outlined in the following README file: README.md

I think that flutterfire_cli is configured properly. I tried to run flutter clean, flutter pub get multiple times, but without result.
$: dart pub global list
flutterfire_cli 0.3.0-dev.16

I am not sure if there is some bug or if I made some mistakes in the configuration. Script fails at line 8, but I cloud find required file in provided path.
#!/usr/bin/env sh
# This file was created by pub v3.1.0-edge.486b3b380e071d6770f8c6a9007e046af84cb888.
# Package: flutterfire_cli
# Version: 0.3.0-dev.16
# Executable: flutterfire
# Script: flutterfire
if [ -f /Users/toma/.pub-cache/global_packages/flutterfire_cli/bin/flutterfire.dart-3.1.0-edge.486b3b380e071d6770f8c6a9007e046af84cb888.snapshot ]; then
  dart "/Users/toma/.pub-cache/global_packages/flutterfire_cli/bin/flutterfire.dart-3.1.0-edge.486b3b380e071d6770f8c6a9007e046af84cb888.snapshot" "$@"
  # The VM exits with code 253 if the snapshot version is out-of-date.
  # If it is, we need to delete it and run "pub global" manually.
  exit_code=$?
  if [ $exit_code != 253 ]; then
    exit $exit_code
  fi
  dart pub global run flutterfire_cli:flutterfire "$@"
else
  dart pub global run flutterfire_cli:flutterfire "$@"
fi

@mavinis Did it work for you?

Hey, sorry for the late response. I just tried the script, and it worked beautifully. Seeing Firebase being automatically configured with Flavors is ~ sweet. Thanks @mxknt, @iJack93, and @thuytrinh.
Some points:

I tested it on Windows and had to make some changes to run it on PowerShell. The GoogleService-Info.plist files were not created, which I kind of expected since manual configuration requires a Mac. However, it's confusing because the FlutterFire CLI didn't complain about it; in fact, it said that the process was successful. The iOS apps were created on the Firebase console, and I could download the files from there, so I'm not sure what the exact problem is. Should I be able to use the CLI to configure iOS apps from Windows at all?
I encountered the same problem as @Garciconx about the "android-out not found," and it was indeed the version problem as mentioned by @gelas7. I was installing the "latest," but the 0.3.0-dev.16 must be installed manually.
--android-out was creating google-services.json in a folder named appandroid outside the project folder. As mentioned above, adding the / fixed it. However, the --out argument doesn't have this problem.

I'm going to try it on Mac later. I just could use some more information about the Windows issue. Thanks, everyone.

Hello 👋 , there was feedback from the latest changes that I need to address before cutting another release. Will let you know when it is released 👍

I'm going to try it on Mac later.

The script works fine on Mac, meaning version 0.3.0-dev.16 is able to generate the right configuration for each platform, considering multiple Flavors associated with their respective Firebase projects - if configured accordingly, as described in this comment: https://github.com/invertase/flutterfire_cli/issues/14#issuecomment-1648682177
One thing I misunderstood at first:
FlutterFire CLI is not meant to create flavors, right? So we still need to configure flavors before running flutterfire. Therefore, the flow for someone using flutter_flavorizr would be:

run flavorizr first, with the firebase option turned off, to create the project's flavors, then
run flutterfire for each build configuration for each flavor, as the mentioned script does.

After that, everything should be ready. Am I missing something?

any update?

I tried this command:
flutterfire configure -p myproject -i=com.mycompany.myproject.dev --platforms=ios

And I got this error:
i Found 1 Firebase projects. Selecting project myproject.
i Selected platforms: ios
i Firebase ios app =com.mycompany.myproject.dev is not registered on Firebase project civstart.
i Registered a new Firebase ios app on Firebase project civstart.
FirebaseCommandException: An error occured on the Firebase CLI when attempting to run a command.
COMMAND: firebase apps:create ios myproject (ios) --bundle-id==com.mycompany.myproject.dev --json --project=myproject
ERROR: Failed to create iOS app for project myproject. See firebase-debug.log for more info.

And the firebase-debug.log has this:
[debug] [2023-08-30T00:20:23.853Z] Command:       /usr/local/bin/firebase /Users/michelfeinstein/.cache/firebase/tools/lib/node_modules/firebase-tools/lib/bin/firebase apps:create ios myproject (ios) --bundle-id==com.mycompany.myproject.dev --json --project=myproject
[debug] [2023-08-30T00:20:23.855Z] CLI Version:   12.5.2
[debug] [2023-08-30T00:20:23.855Z] Platform:      darwin
[debug] [2023-08-30T00:20:23.855Z] Node Version:  v16.16.0
[debug] [2023-08-30T00:20:23.857Z] Time:          Wed Aug 30 2023 10:20:23 GMT+1000 (Australian Eastern Standard Time)
[debug] [2023-08-30T00:20:23.857Z] ----------------------------------------------------------------------
[debug]
[debug] [2023-08-30T00:20:23.867Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
[debug] [2023-08-30T00:20:23.871Z] > authorizing via signed-in user<EMAIL_ADDRESS>[info] Create your IOS app in project myproject:
[debug] [2023-08-30T00:20:23.876Z] >>> [apiv2][query] POST https://firebase.googleapis.com/v1beta1/projects/myproject/iosApps [none]
[debug] [2023-08-30T00:20:23.877Z] >>> [apiv2][body] POST https://firebase.googleapis.com/v1beta1/projects/myproject/iosApps {"displayName":"myproject (ios)","bundleId":"=com.mycompany.myproject.dev"}
[debug] [2023-08-30T00:20:24.549Z] <<< [apiv2][status] POST https://firebase.googleapis.com/v1beta1/projects/myproject/iosApps 400
[debug] [2023-08-30T00:20:24.553Z] <<< [apiv2][body] POST https://firebase.googleapis.com/v1beta1/projects/myproject/iosApps {"error":{"code":400,"message":"Request contains an invalid argument.","status":"INVALID_ARGUMENT"}}
[debug] [2023-08-30T00:20:24.554Z] HTTP Error: 400, Request contains an invalid argument.
[debug] [2023-08-30T00:20:24.793Z] FirebaseError: HTTP Error: 400, Request contains an invalid argument.
    at responseToError (/Users/michelfeinstein/.cache/firebase/tools/lib/node_modules/firebase-tools/lib/responseToError.js:49:12)
    at RetryOperation._fn (/Users/michelfeinstein/.cache/firebase/tools/lib/node_modules/firebase-tools/lib/apiv2.js:285:77)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
[error]
[error] Error: Failed to create iOS app for project myproject. See firebase-debug.log for more info.

@russellwheatley I think there's a bug in the FirebaseOptions generation.

If you want to replicate my project's structure, just create a new project using the vgv cli, it creates 3 environments: production, staging and development. All of them are xcode configurations.

@russellwheatley I am still exploring if these configurations worked. One thing I know that didn't is the dSym Crashlytics upload script. My builds are crashing if I have the upload script there. It says it can't find the file. It's a long exception, but I think it can be resumed to:
    2 warnings generated.
    Unhandled exception:
    ProcessException: No such file or directory
      Command: /Users/michelfeinstein/Projects/myproject/ios/Pods/FirebaseCrashlytics/upload-symbols --build-phase --validate -ai 1:78543256621:ios:c0de76525684b3b1b135c --flutter-project /Users/michelfeinstein/Projects/myproject-flutter/.dart_tool/flutterfire/platforms/ios/buildConfigurations/Release-production/myproject/app_id_file.json
      /Users/michelfeinstein/Library/Developer/Xcode/DerivedData/Runner-aksgfdgfgffrdsppxtgelepkm/Build/Intermediates.noindex/ArchiveIntermediates/production/BuildProductsPath/Release-production-iphoneos/Runner.app.dSYM

@russellwheatley FYI that's how I am handling the initialization of multiple environments:
At main_development.dart
...
final firebaseOptions = DefaultFirebaseOptions.forPlatform(
      android: DefaultFirebaseOptions.androidDevelopment,
      ios: DefaultFirebaseOptions.iosDevelopment,
    );

await Firebase.initializeApp(options: firebaseOptions);
...

Then inside DefaultFirebaseOptions:
// Need to add more platforms here later
static FirebaseOptions forPlatform({FirebaseOptions? android, FirebaseOptions? ios}) {
    Never throwUnsupportedPlatform(TargetPlatform platform) => throw UnsupportedError('DefaultFirebaseOptions are not supported for $platform.');

    return switch (defaultTargetPlatform) {
      TargetPlatform.android => android ?? throwUnsupportedPlatform(defaultTargetPlatform),
      TargetPlatform.iOS => ios ?? throwUnsupportedPlatform(defaultTargetPlatform),
      _ => throwUnsupportedPlatform(defaultTargetPlatform),
    };
  }

@russellwheatley when we add a new Firebase service we have to run flutterfire configure again. Is there a way for us to not have to run this command with all the configurations we already did? Otherwise I will have to run it 6 times

@feinstein - the next release will have a new command flutterfire reconfigure which will reuse values. The values will be stored in the firebase.json file under a flutter key. Release should be soon hopefully, just waiting for the green light and I will update this channel.

If you are creating different environments, you would need to create a different dart configuration file for each one

Will I have to do it manually, or will the CLI help me create those?
At the current version I run the CLI, saved the generated FirebaseOptions, than later I merged them. Managing manually will be a nightmare, so it will be very welcome if we could instruct the CLI to export those for us.

@feinstein  For each environment you configure, use the --out flag to output to a different dart configuration file.

Hey folks, we have just cut a new dev release with a fair number of improvements. Please check the CHANGELOG here for all the features and fixes implemented. Alternatively, run flutterfire --help for available commands.
To install the latest dev version, please run:
dart pub global activate flutterfire_cli 0.3.0-dev.18 --overwrite

Feel free to create new issues regarding this dev release so we can easily track them.
FYI; There are a number of issues on the repo relating to malformed JSON responses which is a result of the Firebase CLI command output being truncated in certain environments. I have elevated this issue with the Firebase team and hope to get it resolved soon 👍

If you also install the latest Firebase CLI npm i -g firebase-tools, they have a fix for malformed JSON responses (what FlutterFire CLI uses under the hood) under certain conditions which they have just released 👍

Can we have this versioning between the CLIs automatic? Otherwise how will we know when we have to update both?

Using flutterfire 0.3.0-dev.16 and the above script from @mxknt I keep receiving the following error:
Unhandled exception:
    PathNotFoundException: Cannot open file, path = '/Users/Me/Developer/firebase.json' (OS Error: No such file or directory, errno = 2)

For some reason it won't recognize the firebase.json in the project directory and looks in another directory. I have been at it for a couple days and could use some insight. I've tried multiple fresh projects and different configurations. It doesn't happen when using simple flutterfire configure.
flutterfire: 0.3.0-dev.16 flutter: 3.10.6 firebase_core: ^2.15.0 firebase_crashlytics: ^3.3.4

Same issue here. Tested with flutterfire cli 0.3.0-dev.15 to 0.3.0-dev.18.
I think a reason might be that FlutterFire CLI generates the scripts FlutterFire: "flutterfire bundle-service-file" and FlutterFire: "flutterfire upload-crashlytics-symbols" with empty Input Files.

Using flutterfire 0.3.0-dev.16 and the above script from @mxknt I keep receiving the following error:
Unhandled exception:
    PathNotFoundException: Cannot open file, path = '/Users/Me/Developer/firebase.json' (OS Error: No such file or directory, errno = 2)

For some reason it won't recognize the firebase.json in the project directory and looks in another directory. I have been at it for a couple days and could use some insight. I've tried multiple fresh projects and different configurations. It doesn't happen when using simple flutterfire configure.
flutterfire: 0.3.0-dev.16 flutter: 3.10.6 firebase_core: ^2.15.0 firebase_crashlytics: ^3.3.4

Same issue here. Tested with flutterfire cli 0.3.0-dev.15 to 0.3.0-dev.18.
I think this is related to the used scripts, as using --ios-target instead of --ios-build-config "and without crashlytics" works normally.

Finally, the reason of this issue was because the app's directory contains space.
i.e: /Users/Me/With Space/MyApp, this will let the path being read as /Users/Me and will try to access /Users/Me/firebase.json
Updating the directory to /Users/Me/With_Space/MyApp should solve it.

I saw some packages providing there one cli like flutter_native_splash using the dart command : dart run flutter_native_splash:create
I think it can be interesting to have a similar usage for this script as it depend of dart. Installing this tool inside flutter dev dependencies instead of global system command is better.
Also, If you have several projects, using several flutter versions, it's a nightmare to handle this tools.
Today, the flutterfire script is launched when we build or run the app. It make sens to put it as project dependency.
Instead of having something like  :
#!/bin/bash
PATH=${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin
flutterfire bundle-service-file ...

We could have something like :
#!/bin/bash
PATH=${PATH}:$FLUTTER_ROOT/bin
dart run flutterfire bundle-service-file ...

This will remove the dependency of the $HOME and I think this will be better for projects using tools like FVM.

So whats the current/latest approach on setting up multiple environments after latest changes on dev ?

...
flutterfire configure \
  --project=myproject-dev \
  --platforms=android,ios \
  --out=lib/main/firebase_options_dev.dart \
  --android-out=android/app/src/dev/ \
  --android-package-name=com.example.app.dev \
  --ios-bundle-id=com.example.app.dev \
  --ios-build-config=Debug-dev \
  --ios-out=ios/config/dev/

Hope that's helpful until a proper guide comes out.

This was super helpful to me, thank you.  I was scratching my head why my CI builds were failing at first and realized I needed release configurations (--ios-build-config=Release-dev instead of --ios-build-config=Debug-dev) for iOS.
Also, because it wasn't obvious to me.  This version of the flutterfire cli adds two build phases for iOS:
FlutterFire: "flutterfire bundle-service-file"
FlutterFire: "flutterfire upload-crashlytics-symbols"

Which allowed me to remove these two build phases:
Copy GoogleService-Info.plist /*(replaced by bundle-service-file)*/
[firebase_crashlytics] Crashlytics Upload Symbols /*(replaced by upload-crashlytics-symbols)*/

From what I could tell, the old [firebase_crashlytics] Crashlytics Upload Symbols was using firebase_app_id_file.json and now that file is no longer generated nor needed with the updated cli and configuration.
And if needed add this to your CI pipeline (codemagic pre build script for example), since you will need flutterfire CLI for those iOS build phases to work.
dart pub global activate flutterfire_cli 0.3.0-dev.18 --overwrite

Please correct me if any of that is inaccurate and thanks to everyone in here for the help!  Seems like it's all working well for me now.

In case you are using Firebase Crashlytics for iOS or macOS, make sure you set debug information format to DWARF with dSYM File, see https://firebase.google.com/docs/crashlytics/get-started?platform=ios#set-up-dsym-uploading

Hey @here, we have released a new dev version:
dart pub global activate flutterfire_cli 0.3.0-dev.19 --overwrite

Please see the CHANGELOG for all the updates it contains: https://github.com/invertase/flutterfire_cli/blob/main/packages/flutterfire_cli/CHANGELOG.md#030-dev19
The upload-symbol (hidden command for internal use only) script that uploads your debug symbols (necessary if you want your dart code de-obfuscated) has changed. Please run flutterfire reconfigure to rewrite the upload symbol script in your Xcode project build phases.
At some point in the new year, the dev release will become the general release and I will be closing this issue out. I've also updated the README file to contain documentation for this release. Hope it helps 🙏

Hi @russellwheatley thank you so much for this great enhancement!
I was not able to use flutterfire reconfigure.
Unfortunately with this command I've these errors:
% flutterfire reconfigure

Failed to write ios "GoogleService-Info.plist" file write for build configuration: "Debug-production". Please report this issue at:https://github.com/invertase/flutterfire_cli. Exception: type 'Null' is not a subtype of type 'String' in type cast
Failed to write ios "GoogleService-Info.plist" file write for build configuration: "Profile-production". Please report this issue at:https://github.com/invertase/flutterfire_cli. Exception: type 'Null' is not a subtype of type 'String' in type cast
Failed to write ios "GoogleService-Info.plist" file write for build configuration: "Profile-development". Please report this issue at:https://github.com/invertase/flutterfire_cli. Exception: type 'Null' is not a subtype of type 'String' in type cast
Failed to write ios "GoogleService-Info.plist" file write for build configuration: "Release-staging". Please report this issue at:https://github.com/invertase/flutterfire_cli. Exception: type 'Null' is not a subtype of type 'String' in type cast
type 'Null' is not a subtype of type 'String' in type cast

With flutterfire configure <options> all is going well.
Maybe I missed something?

@stefan-wisemindlabs hi please refer to this comment https://github.com/invertase/flutterfire_cli/issues/14#issuecomment-1423921383

This feels somewhat counter intuitive and maybe there is room to make it easier to set up in the future?

Agreed. "dev, staging, prod" is such a common setup it would be nice to allow it out of the box.

For my understanding we don’t need 9 times.
Only 3 commands: debug-dev, debug-staging, release-prod
but maybe in your team setup you need more configuration

It's better to have all 9, for example, sometimes we might need to run a production app compiled for debugging, so we can use breakpoints to analyse a specific case that only manifests in production. Also, we distribute staging apps to QAs, and they need a release build, otherwise the performance is not good.