In the latest Stack Overflow developer survey, Firebase was among the most loved technologies in the database area. In the case you are new to Firebase, it’s a cloud-based service provided by Google to enhance mobile app development. Firebase takes the load of managing the in-house mobile application infrastructure. Firebase provides many useful services that make our lives easier, the most used services are:
- Remote database
- Remote config
- Crash reporting (Crashlytics)
Most mobile app developers use Firebase services for a different purpose. Firebase also provides the test lab which offers test devices in the cloud for automated testing. Firebase supports both iOS and Android apps written using native technologies, such as Swift or Kotlin. On top of that, it also supports cross-platform mobile app development frameworks, such as Flutter. Firebase has official documentation on how to configure the Firebase SDK with Flutter apps. In this post, we will provide a step-by-step guide on how to set up the Firebase SDK for Flutter apps and publish those apps securely using the Codemagic CI/CD solution.
In order to follow this guide, you need the following:
- Firebase console (usually linked with the Google account)
- A Flutter project, e.g. Codemagic-Demo
- iOS setup for the Flutter project
Firebase console: Project setup
To get started with Firebase, you need to have a Google account. Visit https://firebase.google.com/ and log in with your Google account credentials. You will be logged in to the Firebase console where you need to set up your project. Once logged in, you can create a project where you can add your iOS, Android or web apps. Detailed information about the Firebase project is available here, but we need to add the project name, project ID and accept the terms & conditions. Now, let’s create a Codemagic Demo project.
Firebase automatically assigns the project ID when the project name is entered, you can change the project ID at this stage. After this stage is complete, you cannot change the project ID anymore.
Once the project is created, you can access the dashboard of the project. Firebase has automatically provisioned all the resources required for the project.
Firebase: App setup
It’s time to add our iOS app to the Firebase project. Flutter creates both the iOS and the Android version of the app. In the Flutter app source code, you can see separate directories for the
android app. In order to add the app to Firebase, you have to complete the platform-specific setup. There is a separate set of instructions for Flutter projects which require fewer steps than the native apps. Let’s add the iOS version of the Flutter app to Firebase by clicking on the iOS icon in the project overview page. You will be asked to enter a few details of the iOS app, such as bundle ID, nickname and App Store ID.
Only the bundle ID is mandatory. You can get the bundle ID of the iOS app from Xcode. Open
ios/Runner.xcworkspace in Xcode and click on Runner in the top left corner. You can then see the bundle identifier on the General tab of your main target.
In our case, it’s
com.codemagic.demo. If you prefer the command line, you can execute the following command by passing the scheme and project workspace of your app.
$ cd ios $ xcodebuild -workspace Runner.xcworkspace/ -scheme Runner -showBuildSettings | grep PRODUCT_BUNDLE_IDENTIFIER
This will print the bundle identifier of your app. You can enter this identifier while registering the app with Firebase.
In the next step, Firebase will ask you to download the
GoogleService-Info.plist file and put it in the iOS app directory. You can also download this anytime later.
In the case of iOS app setup, Firebase will guide you to create a Podfile and install pods, etc. However, you don’t have to perform these steps for the Flutter iOS app setup. Just proceed to the next steps until you see this screen.
At this stage, if you navigate the Firebase dashboard of your project, you will see that our iOS version of the Flutter app has been added to Firebase.
Similarly, you can also set up the Flutter Android app by following the instructions for Android, but we won’t go into this in this tutorial.
Get FlutterFire plugins
As mentioned earlier, Firebase provides different services, like analytics, remote config crash reporting, etc. For each service, there are specific Flutter plugins which are collectively known as FlutterFire. The plugins include platform-specific code to access services and APIs on each platform. As Flutter is a cross-platform mobile application development framework, these plugins can be used for both iOS and Android. You can find the list of all the available plugins on the FlutterFire documentation page.
In order to add Firebase services, we need to get the required plugins and add them to your
pubspec.yaml file. Let’s get the Firebase Core Plugin and add it to the Codemagic-Demo project.
dependencies: flutter: sdk: flutter firebase_core: ^0.2.5
Once you add the dependency, you can download those dependencies using the following command:
$ flutter package get
This command will download the FlutterFire plugins and create the
.flutter-plugins file in the root of the project. This file contains a list of the plugins. Firebase documentation shows how to add the Google Analytics FirePlugin, you can follow the documentation and configure the analytics plugin. However, we will configure a different plugin in this post.
Add the Crashlytics FlutterFire plugin
Let’s add the Crashlytics FlutterFire plugin to our Flutter project. This will report crashes in the Firebase dashboard. In order to add this plugin, you can follow the installation guide here. You need to add the
firebase_crashlytics dependency in the
pubspec.yaml file and run the following command:
$ flutter package get
This command will download the Crashlytics FlutterFire plugin. Once the plugin is downloaded, you can import it in the Flutter app and enable crash reporting for your app as described here.
In order to set up the Codemagic-Demo app for Crashlytics, we need to first set up CocoaPods and enable Crashlytics from Xcode as per the iOS instructions in the plugin documentation here. You have to add another script in the Xcode build phase, as shown below.
If you face any CocoaPods related issues, you may need to run the
pod install command from the
ios directory. This will install all the necessary iOS libraries for the Flutter plugins.
The example app has a working demo of using Firebase and the Crashlytics Flutter plugin. Once the code is embedded in our app and you run the app, we will see that our app is reporting the crash data and other logs to Firebase. The example app has buttons to trigger crashes, throw an error, etc. Flutter logs also show the events as they occur.
Once you trigger the events, you can see those crashes reported in the Firebase console as well.
Now, we have successfully added Firebase for our Flutter app. As the next step, we will securely configure using Firebase on Codemagic CI/CD.
Configure Firebase on Codemagic (encryption)
Codemagic is the official CI/CD solution for Flutter apps. You can set up your Flutter project for continuous integration and continuous delivery within a minute and without any configuration. If you are new to Codemagic, you can read the getting started guide. At this point, we have successfully configured our app with Firebase and Firebase Crashlytics Flutter plugin. We will now have to configure the same on CI. Before proceeding, we have to consider the security aspects of our Firebase account.
In our local configuration, we have downloaded the
GoogleService-Info.plist file and kept it in the
ios directory of the Flutter app. This file contains sensitive data, like the API key and information about the app. This file shouldn’t be checked in to source control or exposed to the world. We have to take certain steps to secure our sensitive data.
Ignore GoogleService-Info.plist in SCM
First, we have to ignore the
GoogleService-Info.plist file to avoid it being checked in to the source control manager, such as Git. You can add this file to your
.gitignore file depending on where you keep the sensitive file. For example:
Once the file added to the
.gitignore list, it cannot be committed to source control by mistake.
Encrypt GoogleService-Info.plist with a strong key
At this stage, we have ensured that we won’t commit the
GoogleService-Info.plist file to source control. However, the continuous integration server will expect to find this file in order to successfully build the Flutter app. There are several ways to encrypt sensitive files with a strong encryption password and decrypt them on the CI server using the same password. On the local macOS machine, you can execute the following command to encrypt the file.
$ openssl enc -aes-256-cbc -salt -in ios/Runner/GoogleService-Info.plist -out ios/Runner/GoogleService-Info.enc -k "YOUR_SECRET_PASSWORD"
This will create an encrypted version of the file,
ios/Runner/GoogleService-Info.enc, which can be safely checked in to source control. However, your encryption password should be super strong. This encryption password will be used on Codemagic to decrypt the file.
Decrypt GoogleService-Info.enc on Codemagic using a secret environment variable
At this stage, we have
ios/Runner/GoogleService-Info.enc checked in to the repository. Before building, we have to decrypt the file using the encryption password used earlier. Codemagic provides a way to securely store sensitive information using environmental variables. In the app settings, you can expand the Environment variables section and add a variable
FIREBASE_KEY with the value of your encryption password. Don’t forget to check Secure to ensure that the value won’t be displayed in the build logs.
Now that we have created the variable
FIREBASE_KEY, we can use it in the custom script before the build.
In the Codemagic app setting, before the build stage, click on the + button to add the following pre-build script.
#!/bin/bash openssl enc -aes-256-cbc -d -in ios/Runner/GoogleService-Info.enc -out ios/Runner/GoogleService-Info.plist -k "$FIREBASE_KEY" openssl enc -aes-256-cbc -d -in ios/Runner/GoogleService-Info.enc -out ios/GoogleService-Info.plist -k "$FIREBASE_KEY" echo "Decrypted GoogleService-Info.plist Successfully using your strong encryption key set in the Codemagic ENV variable section " echo "Listing iOS Directory to confirm the GoogleService-Info.plist is there! " ls ios/Runner/
In the Codemagic UI, this script will look like this:
Click the Save button so that the script will be saved for the pre-build phase. You don’t need to worry about removing the files as the builder VMs are wiped clean after every build.
In the pre-build phase, we will see that the file is available for the build. The build logs look like this:
Now that we have securely added the sensitive file to Codemagic as a secure environment variable, we can see that the Codemagic build is successfully passed.
We have successfully built the Flutter app with Firebase on Codemagic using encryption.
Firebase on Codemagic (encoding)
There is another technique that can be used for securing the content of the sensitive files on the CI server. There is already a blog post on how to use the encoding technique on Codemagic to secure the Firebase sensitive files. In this approach, we are using an encoding technique rather than an encryption technique. It’s a very similar approach but we have to encode the file locally and decode while executing on Codemagic. The
GoogleService-Info.plist file can be encoded locally using the following command:
$ openssl base64 -in ios/GoogleService-Info.plist
This command will print the encoded content which we need to paste in the Codemagic environment variable.
In the Codemagic app settings, expand the Environment variables section and add the variable
FIR_ENCODE which can be used to decode the file back to the original.
In the case of iOS, we have to run the custom script in the pre-build phase. Add the following pre-build script in Codemagic.
#!/bin/sh echo "==Decoding GoogleService-Info.plist File" echo $IOS_FIREBASE | /usr/local/Cellar/base64/1.5/bin/base64 --decode > $FCI_BUILD_DIR/ios/GoogleService-Info.plist echo "==Successfully Decoded GoogleService-Info.plist File"
In Codemagic, it looks like this:
After this script, we will get the original
GoogleService-Info.plist file and carry on with our build execution. You can read the detailed steps of the encoding technique in this blog post.
We have now seen how to integrate Firebase into Flutter apps and run the apps securely on the Codemagic CI/CD service. When you’re using encryption, the sensitive file is still stored in the repository, although in encrypted form. With environment variables, you can securely store the file on Codemagic instead of the repository. You can choose whichever technique is more convenient for your project setup.
$ git clone [https://github.com/Shashikant86/Codemagic-Demo](https://firebase.google.com/ "https://firebase.google.com/") $ cd Codemagic-Demo $ git checkout firebase
In case you encounter any issues related to CocoaPods, you need to set up CocoaPods using the
pod init command and probably need to run
pod install locally.
Firebase provides out-of-the-box support for Flutter apps and there are lots of FlutterFire plugins available. With the combination of Flutter, Firebase and Codemagic, you can deploy the Flutter apps securely with Firebase features enabled in the production.