invertase / flutterfire_cli

A CLI to help with using FlutterFire in your Flutter applications.
Apache License 2.0
165 stars 47 forks source link

Support for multiple scheme dev, staging, prod #14

Closed ghensto closed 2 months ago

feinstein commented 1 year ago

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.

kinex commented 1 year ago

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.

Yes, this is the problem that worries me too.

russellwheatley commented 1 year ago

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

Screenshot 2022-10-04 at 16 45 19

@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.

ollyde commented 1 year ago

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 😎

cedvdb commented 1 year ago

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.

feinstein commented 1 year ago

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.

feinstein commented 1 year ago

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:

Screenshot 2022-10-04 at 16 45 19

@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.

ollyde commented 1 year ago

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.

feinstein commented 1 year ago

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.

feinstein commented 1 year ago

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

feinstein commented 1 year ago

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

ollyde commented 1 year ago

I filed this issue a few times and it was implemented with config which works on iOS and is broken on Android.

The issue is not getting out of hand, we are discussing it right now, please don't lock it.

--

This is definitely functionality that applies to most people, I worked with more than 50 platforms in the last 4 years (it work with accelerator devs) and this is the number 1 complaint.

ollyde commented 1 year ago

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.");
    }
  }
}
ollyde commented 1 year ago

@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 πŸ„πŸ»β€β™‚οΈ

@feinstein which 'major' bank doesn't use staging, alpha, dev, prod-data for QA? Curious.

feinstein commented 1 year ago

I am just saying here's not the place to discuss this, if you already filed, so discuss it there. Otherwise things get off topic, and the thread becomes a mess, and nothing gets done.

erf commented 1 year ago

@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 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?

LutfiGarzon commented 1 year ago

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 πŸ‘

WalidChebaro commented 1 year ago

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

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

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}"

Link Binary With Libraries

Salakar commented 1 year ago

@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:

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

LutfiGarzon commented 1 year ago

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

russellwheatley commented 1 year ago

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:

  1. 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).
  2. 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.
  3. 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.
  4. 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

  1. If you do not specify a path, the CLI will just revert to existing behaviour for each platform.
  2. 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.
  3. 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!

agonhajdari commented 1 year ago

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.

ablbol commented 1 year ago

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:

  1. 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).
  2. 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.
  3. 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.
  4. 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

  1. If you do not specify a path, the CLI will just revert to existing behaviour for each platform.
  2. 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.
  3. 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?

krishnatejakanchi commented 1 year ago

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

krishna-pietech commented 1 year ago

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

stact commented 1 year ago

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:

  1. 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).
  2. 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.
  3. 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.
  4. 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

  1. If you do not specify a path, the CLI will just revert to existing behaviour for each platform.
  2. 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.
  3. 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 [

image

russellwheatley commented 1 year ago

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

russellwheatley commented 1 year ago

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.

asaarnak commented 1 year ago

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

  1. On Linux and Mac GoogleService-Info.plist file were not generated, i added it manually to --ios-out folder.
  2. On Linux no errors or warnings were shown when project.pbxproj was not updated.
  3. 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
cedvdb commented 1 year ago

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, this is minor though.

AristideVB commented 1 year ago

@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 ? πŸ™‚

russellwheatley commented 1 year ago

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 once it is ready. I will also address the bugs mentioned by @AristideVB & @asaarnak πŸ™

cedvdb commented 1 year ago

Depending on if some assumptions can be made when there are flavors, a less manual flutterfire configure:flavor dev might be a nice addition.

I suppose the following assumptions can be made:

AlexandrLevin-SelfTable commented 1 year ago

@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 commented 1 year ago

That's an interesting idea, @cedvdb. Something we can perhaps think about in a future release πŸ‘.

@AlexandrLevin-SelfTable - yeah, I guess that should handle spaces in paths. Can fix that I think.

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.

Which script are you referring to exactly?

AlexandrLevin-SelfTable commented 1 year ago

@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.

russellwheatley commented 1 year ago

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.

I hope I understood you correctly πŸ˜„

russellwheatley commented 1 year ago

@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.

russellwheatley commented 1 year ago

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.

asaarnak commented 1 year ago

@russellwheatley Tested this command:

flutterfire configure
 --overwrite-firebase-options
 --project=myapp-development
 --out=lib/config/firebase/firebase_options_dev.dart
 --ios-bundle-id=com.myapp.dev
 --android-package-name=com.myapp.dev
 --android-out=android/app/src/development
 --ios-out=ios/Firebase/development
 --ios-build-config=Debug-development
 --debug-symbols-ios
 --yes
  1. The GoogleService-Info.plist file is created in wrong folder ios/Firebase should be in ios/Firebase/development folder.
  2. The Android service file android/app/src/development/google-services.json is not created.
  3. Do we need to install flutterfire_cli to CI(Codemagic) to run hidden commands bundle-service-file and upload-crashlytics-symbols? The shellScript in project.pbxproj seems to contain local absolute path
    shellScript = "\n#!/bin/bash\nPATH=${PATH}:/Users/asaarnak/A/PROGRAMS/flutter/bin:/Users/asaarnak/.pub-cache/bin\nflutterfire bundle-service-file --plist-destination=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app --build-configuration=${CONFIGURATION} --platform=ios --apple-project-path=${SRCROOT}\n";
russellwheatley commented 1 year ago

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 πŸ€”

russellwheatley commented 1 year ago

@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). If you require FFCLI to run on your CI, it will have to be installed.

russellwheatley commented 1 year ago

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.

asaarnak commented 1 year ago

Rerun same command with filenames.

  1. 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
  2. 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 commented 1 year ago

@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?

russellwheatley commented 1 year ago

Rerun same command with filenames.

  1. 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
  1. 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.

  1. The point about firebase.json might be a bug, I can look into that. I thought they'd be updated but perhaps not.
  2. Yes, it is relative from your project. Absolute paths are not accepted. Perhaps we can implement in the future.
  3. 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.

asaarnak commented 1 year ago

Thanks! Is npm install -g firebase-tools and dart pub global activate flutterfire_cli 0.3.0-dev.15 --overwrite enough? Or we would need to firebase login also in CI before running flutter build?

russellwheatley commented 1 year ago

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.

stact commented 1 year ago

Hi @russellwheatley Thank you again for this great achievement πŸ’― let's go to the moon!

Quick question regarding the rework on ios-build-config. Does it means that we need to launch 3 times the command-line to get stuff ready? (I'm using vgv cli too). Indirectly 9 times (dev, stg, prd) ^^)

$ flutterfire configure [...] --ios-build-config=Debug-staging
$ flutterfire configure [...] --ios-build-config=Profile-staging
$ flutterfire configure [...] --ios-build-config=Release-staging

Thank you for your feedback!

russellwheatley commented 1 year ago

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.