Creating beautiful mobile applications using Flutter and Firebase

shivankawasthi

Authored by:

  • Shivank Awasthi (@shivankawasthi) Strategic Cloud Engineer, Google
  • Utkarsh Bhardwaj (@bhardwaju) Cloud Migration Consultant, Google

mobile-apps-flutter-firebase.png

Over the years, developers have struggled with cross-platform development. With the evolution of the mobile industry, it became imperative that any popular application in the market needs to be available on the most popular platforms (i.e. Android and iOS). But due to significant differences in the overall design and architecture of these platforms, it was really difficult to use a common technology that can create applications for both. 

In most cases, developers reject cross-platform development and propose native development instead, as Xamarin, React Native, Ionic and other cross-platform frameworks have more drawbacks than benefits - be it animation customization or support of all android devices and operational systems. On top of that, if developers are able to make two versions of the same application, their look and feel is not consistent. This happens due to the differences in the internal libraries for these platforms.

Then came Flutter and it changed the game.

Background

Native apps are software applications that are used in a platform. The programming language of native apps are based on the platform. It is designed specifically for operating systems. So whatever the hardware and software that the O/S uses, will be used by native apps too. 

Disadvantages of native app development

1. Cost

The overall cost involved in the development and maintenance of a native app is considerably higher. This is due to the fact that there should be separate versions of the same application. A substantial amount is needed to maintain the app. But still, native apps are cost effective in the long run.

2. Development

Developing a native app is a complex process since separate developers are needed for each platform. For example, different developers must be hired to develop Android and IOS versions of the same application. Moreover, it is not an easy task to develop native apps. It is incorporated with tough challenges, as the app needs to be up-to-date and compliant with the latest changes in both platforms.

3. Time consuming

Since native apps are developed for multiple platforms, it requires more time. Native apps may require a significant amount of creation time compared to their counterparts. Developers of native apps have to take time to write codes for specific O/S, and a significant portion of time is often dedicated to make the look and feel consistent for applications designed for both platforms.

4. Updates

Developers often come up with new updates in native apps for various reasons - most often for fixing bugs and glitches. Hence, necessary updates need to be implemented in the app store so that users will be able to download them. Now the problem comes if the user isn't aware of such updates or skips them to save storage space.

Flutter

Flutter is an open-source project hosted on GitHub with contributions from Google and the community. Flutter uses Dart, a modern object-oriented language that compiles to native ARM code and production-ready JavaScript code. 

Flutter - a simple and high performance framework based on Dart language, provides high performance by rendering the UI directly in the operating system’s canvas rather than through native framework. This ensures that the application’s look and feel remains consistent irrespective of the platform, as the application is directly being plotted and created at the pixel level.

Advantages of Flutter

1. Same UI and business logic in all platforms

We know that essentially any cross-platform framework provides a way to share codebase between the target platforms. But there are no such application frameworks that allow sharing both the UI code and the UI itself, besides Flutter.

flutter-app-ui.png

Image source

2. Reduced code development time

Flutter’s “hot reload” feature, in turn, allows seeing the applied changes almost instantly, without even losing the current application state. And this is exactly what makes Flutter app development several times faster due to the increased development speed. The way this feature works is that in case of hot reload, it preserves the parent widget tree to ensure that only the code that has been modified is getting changed.

flutter-app-services-ui.png

Image source

3. Increased time-to-market speed

This one is pretty straightforward. Flutter development framework functions quicker than its alternatives. In most cases, you can expect a Flutter app to require at least two times fewer man-hours compared to the same app developed separately for Android and iOS. The main reason is simple: you don’t have to write any platform-specific code to achieve the desired visuals in your application. Any 2D-based UI can be implemented in Flutter without interacting with a native application counterpart.

4. Custom, animated UI of any complexity available

One of the biggest advantages of Flutter is the ability to customize anything you see on the screen, regardless of how complex it may be. While it’s usually possible to do a very custom UI on native platforms as well, the amount of effort required differs by the order of magnitude. Here’s an example of such a simple, yet custom UI.

flutter-mobile-app-example.png

Image source

Firebase

Firebase is an app development platform that helps you build and grow apps and games users love, backed by Google and trusted by millions of businesses around the world.

  • Firebase helps in building powerful apps. Firebase allows the developer to spin up their backend without managing servers and scale effortlessly to support millions of users with Firebase databases, machine learning infrastructure, hosting and storage solutions, and Cloud Functions.
  • Firebase improves app quality in less time with less effort. Firebase simplifies testing, triaging, and troubleshooting.
  • Firebase helps in boosting the user engagement with rich analytics, A/B testing, and messaging campaigns. Firebase understands and gathers insights about your users to better support and retain them. Firebase runs experiments to test ideas and uncover new insights. 

Integrating Firebase with Flutter 

Let’s add Firebase to your Flutter application…

1. Create a Firebase project
Assuming you’ve already created your account for Firebase and are logged in, click on the get started icon -> Add Firebase to your project. Go with the flow and provide the necessary information to create your first project with Firebase.

create-firebase-project.png

 2. Register your app with Firebase

  • In the project overview page, select the iOS icon to launch the set up flow. If you have already added the app to your project, click on add app to provide details of your application.
  • Provide your app’s bundle ID. Find this bundle ID from your open project in XCode. Select the top-level app in the project navigator, then access the General tab. The Bundle Identifier value is the iOS bundle ID (for example, com.yourcompany.ios-app-name).
  • You may also provide optional details like App NickName and App Store ID.
  • Register your app.

add-firebase-ios-app.png

3. Add Firebase configuration file

  • Click Download GoogleService-Info.plist to obtain your Firebase iOS config file (GoogleService-Info.plist). You can download your Firebase iOS config file again at any time. Make sure the config file is not appended with additional characters, like (2).
  • Using XCode, move the file into the Runner/Runner directory of your Flutter app.
  • Back in the Firebase console setup workflow, click Next to skip the remaining steps.

4. Add Firebase plugins

Flutter uses plugins to provide access to a wide range of platform-specific services, such as Firebase APIs. Plugins include platform-specific code to access services and APIs on each platform.

Firebase is accessed through a number of different libraries, one for each Firebase product (for example: Realtime Database, Authentication, Analytics, or Storage). Flutter provides a set of Firebase plugins, which are collectively called FlutterFire.

Since Flutter is a multi-platform SDK, each FlutterFire plugin is applicable for both iOS and Android. So if you add any FlutterFire plugin to your Flutter app, it will be used by both the iOS and Android versions of your Firebase app.

Adding the FlutterFire plugin, step-by-step

  1. From the root directory of your project, open the pubspec.yaml file and add the following code:

flutterfire-plugin-dependencies.png

  1. Add the plugin for the Firebase feature you want to use in your app :

flutter-firebase-dependencies.png

  1. Run flutter packages get.

Use case: Building an app for users where they’re storing user data and also authenticating into the app

For our use case here, we are building an app with Flutter and integrating it with Firebase in the backend for Authentication and Firebase Realtime Database.

Get started with Firebase Authentication on Flutter

Add Firebase Authentication to your app

  1. From the root of your Flutter project, run the following command to install the plugin: flutter pub add firebase_auth
  2. Once complete, rebuild your Flutter application: flutter run
  3. Import the plugin in your Dart code: import 'package:firebase_auth/firebase_auth.dart';

To use an authentication provider, you need to enable it in the Firebase console. Go to the Sign-in Method page in the Firebase Authentication section to enable Email/Password sign-in and any other identity providers you want for your app.

firebase-authentication-mobile-app.png

Image source

(Optional) Prototype and test with Firebase Local Emulator Suite

Before talking about how your app authenticates users, let's introduce a set of tools you can use to prototype and test Authentication functionality: Firebase Local Emulator Suite. If you're deciding among authentication techniques and providers, trying out different data models with public and private data using Authentication and Firebase Security Rules, or prototyping sign-in UI designs, being able to work locally without deploying live services can be a great idea.

The second part is trickier. Firebase provides two database options: Cloud Firestore and Realtime Database. For our use case, both are legitimate options. It depends on the need to handle big amounts of data or even perform queries on it, so here we are going with Realtime Database. But Cloud Firestore would also work just fine, and you might as well use it for other upcoming features. To decide for yourself what will suit you better, Google provides a test, so you can test it for your application yourself.

The Realtime Database - yes, it’s a NoSQL database (as well as Cloud Firestore) - has its implications. So if you’re looking into the direction of any Firebase data store, you need to keep that in mind. Even though some of our models are quite complex, they don’t have many relations between them. They can also be flattened into simple JSON types like the one below, for example.

json-realtime-database.png

Architecture

We will follow the Clean Architecture principles in our module structure (presentation / data / domain). So if we ever want to move on from Firebase, we can plug in a new data module and be done with it.

In the presentation layer, we use the BloC pattern via this library, usually a bloc-per-page structure. 

BLoC stands for Business Logic Components. The gist of BLoC is that everything in the app should be represented as a stream of events: widgets submit events, and other widgets will respond. BLoC sits in the middle, managing the conversation. Dart even comes with syntax for working with streams baked into the language.The bloc shouldn’t know anything about the UI and the widget should be as business logic agnostic as possible. If you don’t know what BloC is yet, we highly recommend reading about it here.

firebase-architecture-BLoC.jpeg

Image source

Local storage

Our users can start their projects from the app and track their progress. To do that, we save the pattern details and the user's progress into a local database. One of the future features can be to also synchronize this data with the backend so that users can continue their progress on another device, but that’s not yet implemented.

CI/CD: GitLab + Firebase AppDistribution

This was also a no-brainer because the Bitrise + Firebase App Distribution works for all apps, and it works like a charm. The Firebase App Distribution part has no problems. Gitlab is an absolutely amazing and highly customizable CI tool.

gitlab-cicd-pipeline.png

Image source

GitLab CI/CD pipelines are configured using a YAML file .gitlab-ci.yml in the root of the project folder. There are different stages in the pipeline but the two most important stages are the Build and  Test & Deploy stages, which can be seen above.

Limitations 

Because testing new patterns straight on production isn’t a very clever or user-friendly idea, we should make different flavors of our app before releasing it to the users.

Even though flavors on Android and iOS are pretty standard, the same thing can’t be said about Flutter. 

Flavors 

Flavors are so amazing. Just like how ice cream has different flavors and everyone loves them, your application may have different flavors too! By using flavors, you can create different versions of your app, meaning you can generate different versions or variants of your app using a single code-base.

Why do we need flavors?

They are just comfortable. They let you define some build configuration and switch them as you want. For example, you could have one flavor for development, and one for production. You can set different URLs for API calls or different icons and app names. With a click you’re ready to develop or to release your great application.

When to use flavors?

  • Let’s say for a scenario in which you have a paid and a free version of the app, you can limit the features in the free app and expose all the other features in a paid version for the app.
  • When you wish to address the issue of having a separate project code for each version of the app, while still having one project code.
  • For white labeling (these are apps that are developed by a certain company, and they are rebranded and resold by other companies).

Disadvantages of flavors

  • As a best practice, we will go for different Firebase instances so that the logic could be separate and not mixed up unintentionally, but because of this, we would now have to create and manage more Firebase instances.
  • IDEs (integrated development environments) sometimes take time to build the project after switching between variants.
  • The more variants, the greater the complexity, which in turn makes it harder to maintain the code-base.
  • It can be overwhelming for a new developer in the team to manage and switch between different environments.

Overall, these limitations are not too major to prevent the developers from using flavoring with Flutter.

References