iOS and multiple Firebase environments

Alex Marchant
Mac O’Clock
Published in
6 min readAug 3, 2020

The problem

Firebase can be a tricky customer to work with, especially when it comes to utilising multiple environments so we can segment our data.

The main problem is caused by the ‘GoogleService-Info.plist’ (GSIP) file since we cannot have multiple versions of the same file in the location the Firebase SDK requires it to be.

Therefore, what we can do is dynamically add the correct GSIP file to the required location when we build and run the app depending on the scheme we are using in Xcode.

The Fix

I am going to be using my app PTHub (www.pthub.app) as an example.

1) Set up your Firebase environments and download each of the GSIP files.

I set up my environments to each have a unique bundle identifier that denotes which app environment I am using.

I would recommend you do the same as it is the easiest way to ensure your environments are separated and it ensures you don’t run into issues further down the line.

The pattern I went with is:

TEAMNAME.APP NAME-ENVIRONMENT NAME.ADDITIONALINFO

Environment Name is whatever environment this app links to: ‘dev’, ‘prelive’, ‘live’, etc.

You need to remember/write these Bundle ID’s down because you will need them later when we set up the Configurations in Xcode.

Here are the 3 projects I setup:

Firebase Environments

Here is an example of the Bundle ID for my ‘pthub-dev’ environment:

Ensure you have your required Firebase SDK’s installed (I have used CocoaPods for my project.)

2) Open your Xcode project and create a folder named ‘Config’ at the same folder level you would find the AppDelegate.swift/Main.storyboard files on the creation of a project.

Config Folder added

3) In the ‘Config’ folder, create sub-folders denoting the environment this GSIP file points to.

Sub-folders added to Config folder

4) Add the GSIP files to their respective folder but ensure no targets are ticked when you add the file.

Confirm the name of each file is ‘GoogleService-Info.plist’

GSIP Files added to the project

5) Follow this article for setting up multiple schemes & configs in your Xcode project and place the .xcconfig files in their respective ‘Config’ sub-folder alongside your GSIP files.

Added custom config files

6) In each of your .xcconfig files, add a new variable such as ‘ENVIRONMENT’ to denote which environment is being used.

I have used the variable ‘APP_BUNDLE_ID’ which has a value of the custom Bundle ID I set up to be used in the schemes and by my Firebase projects.

7) Go to your project, click your app’s target and open the build phases tab.

8) Click the plus in the top left and add a ‘New Run Script Phase’ named ‘Firebase Environment Selection’.

If you use Crashlytics in your app, move this build phase before the Crashlytics phase.

Added Firebase Environment Selection to build phases

9) Dynamically add the GSIP file in your build phase.

In my example, I have 3 environments setup: ‘dev’, ‘prelive’ and ‘live’ so, in the ‘Firebase Environment Selection’ build phase, I need to figure out which environment the app is currently building so Xcode can copy & paste the correct GSIP file. Therefore, the code below is an example of these three environments. You can add/remove as your requirements dictate.

You will need to add your respective values to the code, these are denoted by ‘__YOUR-*-VALUE__’

For example, in my .xcconfig files, I use the variable ‘APP_BUNDLE_ID’ to define which environment I am using and then compare it to a string value.

In your case, you might have used a different variable name in the .xcconfig file and will need to update the string comparison to match the values in the .xcconfig files.

Place the following code into your ‘Firebase Environment Selection’ build phase code area

PLEASE BE AWARE:

COPY AND PASTING CODE CAN CAUSE THE SPEECH MARKS TO BECOME INVALID CHARACTERS.

REPLACE THE SPEECH MARKS AFTER COPYING AND PASTING THE CODE INTO YOUR BUILD PHASE

INFO_PLIST=GoogleService-Info.plist

DEVELOPMENT_INFO_PLIST=${PROJECT_DIR}/${TARGET_NAME}/Config/__YOUR-ENVIRONMENT-VALUE__/${INFO_PLIST}

PRELIVE_INFO_PLIST=${PROJECT_DIR}/${TARGET_NAME}/Config/__YOUR-ENVIRONMENT-VALUE__/${INFO_PLIST}

RELEASE_INFO_PLIST=${PROJECT_DIR}/${TARGET_NAME}/Config/__YOUR-ENVIRONMENT-VALUE__/${INFO_PLIST}

echo “Checking ${INFO_PLIST} in ${DEVELOPMENT_INFO_PLIST}”

if [ ! -f $DEVELOPMENT_INFO_PLIST ] ; then

echo “Development GoogleService-Info.plist not found.”

exit 1

fi

echo “Checking ${INFO_PLIST} in ${PRELIVE_INFO_PLIST}”

if [ ! -f $PRELIVE_INFO_PLIST ] ; then

echo “Prelive GoogleService-Info.plist not found.”

exit 1

fi

echo “Checking ${INFO_PLIST} in ${RELEASE_INFO_PLIST}”

if [ ! -f $RELEASE_INFO_PLIST ] ; then

echo “Release GoogleService-Info.plist not found.”

exit 1

fi

PLIST_DESTINATION=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app

echo “Copying ${INFO_PLIST} to final destination: ${PLIST_DESTINATION}”

if [ “${__YOUR-XCCONFIG-VARIABLE-NAME__}” == “__YOUR-XCCONFIG-VARIABLE-VALUE__” ] ; then

echo “Copied ${RELEASE_INFO_PLIST}.”

cp ${RELEASE_INFO_PLIST} ${PLIST_DESTINATION}

elif [ “${__YOUR-XCCONFIG-VARIABLE-NAME__}” == “__YOUR-XCCONFIG-VARIABLE-VALUE__” ] ; then

echo “Copied ${PRELIVE_INFO_PLIST}.”

cp ${PRELIVE_INFO_PLIST} ${PLIST_DESTINATION}

else

echo “Copied ${DEVELOPMENT_INFO_PLIST}.”

cp ${DEVELOPMENT_INFO_PLIST} ${PLIST_DESTINATION}

fi

PLEASE BE AWARE:

COPY AND PASTING CODE CAN CAUSE THE SPEECH MARKS TO BECOME INVALID CHARACTERS.

REPLACE THE SPEECH MARKS AFTER COPYING AND PASTING THE CODE INTO YOUR BUILD PHASE

Here is an example of me implementing this code on a fresh project:

Example of customised script

10) Finally, if you’re using Crashlytics in your app, you will need to update your Crashlytics build phase to point to correct GSIP file.

PLEASE BE AWARE:

COPY AND PASTING CODE CAN CAUSE THE SPEECH MARKS TO BECOME INVALID CHARACTERS.

REPLACE THE SPEECH MARKS AFTER COPYING AND PASTING THE CODE INTO YOUR BUILD PHASE

INFO_PLIST=GoogleService-Info.plist

DEVELOPMENT_INFO_PLIST=${PROJECT_DIR}/${TARGET_NAME}/Config/__YOUR-ENVIRONMENT-VALUE__/${INFO_PLIST}

PRELIVE_INFO_PLIST=${PROJECT_DIR}/${TARGET_NAME}/Config/__YOUR-ENVIRONMENT-VALUE__/${INFO_PLIST}

RELEASE_INFO_PLIST=${PROJECT_DIR}/${TARGET_NAME}/Config/__YOUR-ENVIRONMENT-VALUE__/${INFO_PLIST}

echo “Initialising Crashlytics”

“${PODS_ROOT}/FirebaseCrashlytics/run”

if [ “${__YOUR-XCCONFIG-VARIABLE-NAME__}” == “__YOUR-XCCONFIG-VARIABLE-VALUE__” ] ; then

“${PODS_ROOT}/FirebaseCrashlytics/upload-symbols” -gsp “${RELEASE_INFO_PLIST}” -p ios “${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}”

elif [ “${__YOUR-XCCONFIG-VARIABLE-NAME__}” == “__YOUR-XCCONFIG-VARIABLE-VALUE__” ] ; then

“${PODS_ROOT}/FirebaseCrashlytics/upload-symbols” -gsp “${PRELIVE_INFO_PLIST}” -p ios “${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}”

else

“${PODS_ROOT}/FirebaseCrashlytics/upload-symbols” -gsp “${DEVELOPMENT_INFO_PLIST}” -p ios “${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}”

fi

PLEASE BE AWARE:

COPY AND PASTING CODE CAN CAUSE THE SPEECH MARKS TO BECOME INVALID CHARACTERS.

REPLACE THE SPEECH MARKS AFTER COPYING AND PASTING THE CODE INTO YOUR BUILD PHASE

Build & Test

To switch the environment that you are using, you will need to switch the scheme you are building with.

That’s it, run and test your app and you should be all set to go using multiple Firebase environments.

P.S.

You may get an error around incorrect/inconsistent Bundle ID’s being used in the GSIP file when changing schemes resulting in the wrong Firebase environment being used. This error means something is incorrect with the configuration of your: .xcconfig files, Configurations or the values you have used in the Run Script.

  1. Go back through this article to ensure nothing is missing/incorrect.
  2. Recheck the values you are using in the Run Script.
  3. Ensure the schemes are correctly setup.
  4. Check all the above again

If you are still having issues, send me a message on LinkedIn (link in my profile)

--

--