Managing user presence in Cloud Firestore using Flutter

Souvik Biswas
Flutter Community
Published in
7 min readJan 7, 2021

While building an application which deals with messaging, the most important part is keeping track of whether they are online/offline (formally known as User Presence). But, if you are using Firebase Cloud Firestore as your database, then handling this is pretty challenging.

In this article, I will show you how to manage user presence in a Flutter app using Cloud Firestore as it’s database.

We will be using Realtime Database and Cloud Functions to achieve this.

Disclaimer: Knowledge of JavaScript is recommended, as you have to write Cloud Functions using JS.

Sample app

The app that we will be building for this demonstration will contain a simple Google Sign In for the authentication of users on Firebase. Firestore database will be used for storing some user-specific information. User presence and last seen time will be tracked using a combination of Realtime Database, Cloud Functions, and Firestore.

Presence tracking in action

Firebase set up

As we are using Firebase as the backend for our app, it is required to complete the Firebase set up first.

You can follow this article in order to complete the Firebase and Google Sign In setup.

Some brief about the steps you need to follow:

  • Create a new project using the Firebase console.
  • Configure the Android & iOS app to use Firebase.
  • Add your support email by going to the Firebase project settings.
  • Enable Google Sign In on Firebase Authentication.
  • Complete the platform-specific configuration to use Google Sign In.
  • Enable Cloud Firestore and Realtime Database.
  • Specify Security rules for both of them.

For now, you can just define the security rules, so that it checks if the user is authenticated:

If you are working on a production app, don’t forget to modify these security rules for better protection.

Let’s start building the app now.

In this tutorial, I will focus on the major functionalities of the app. So, if you want to see the UI code of the app, check out my GitHub repo (present at the end of this article).

Required plugins

Before diving into code, add the plugins required for building the app to your pubspec.yaml file:

Authenticating user

We will define two methods for authenticating a user to Firebase using Google Sign In. Create a new file called authentication.dart, and add the following methods:

  • signInWithGoogle()
  • signOutGoogle()
  • getUser()

In the signInWithGoogle() method, we will first initialize the Firebase app, and then retrieve the credentials from the Google account to authenticate the user in Firebase.

The signOutGoogle() method will help the user to sign out of the currently logged in Google account.

You can define one more method, called getUser() to retrieve the user information when an already logged in user returns back to the app (also known as auto-login).

I am not going deep into these methods, you can check out this article for a more detailed explanation (with code snippet), or find the GitHub repo of this app at the end of this article.

Storing data on Firestore

Some of the general user information, and most importantly user presence and last seen time should be stored in the Cloud Firestore. Create a new file called database.dart, we will be defining two basic methods there:

  • storeUserData(): To upload the user information to the Firestore when a new user logs in.
  • retrieveUsers(): To retrieve all user details from Firestore.

The database structure of Firestore will be like this:

Inside a class called Database, we will first store a reference to the main collection of Firestore.

Let’s define the storeUserData() method which will store the user details under a document according to their uid.

Here, you can use a model class to easily handle the data. In this example, I am using a model class called User:

In order to retrieve the list of all users, you can define the retrieveUsers() method like this:

Handling user presence

The problem with Cloud Firestore is, it doesn’t provide any method using which you can track when the user navigates away from this app or terminates it. But, another Firebase service called Realtime Database provides a dedicated method to track user presence, named as onDisconnect(). Whenever the client loses the connection to the database, this gets triggered automatically.

Define a new method inside the database.dart file called updateUserPresence(). This method will store the user presence and last seen time to the Firebase Realtime Database.

You may also skip storing the last_seen property on Realtime Database, because we can directly set it using Cloud Functions in the later step.

As the onDisconnect() method gets triggered, the presence status will be updated on the Realtime Database.

Syncing user presence

Now coming to the most important part of the article, synchronizing user presence information present on the Realtime database to the Cloud Firestore. You can use an awesome service provided by Firebase called Cloud Functions, which helps to run backend code on Google’s servers in response to the events triggered by Firebase features.

In order to write and deploy Cloud Functions, you will need to initialize Firebase using Firebase CLI tools:

npm install -g firebase-tools
  • Login to your Firebase account:
firebase login
  • Initialize Firebase by running the following inside the project directory:
firebase init
  • Choose Functions: Configure and deploy Cloud Functions from the list.
  • In the Project Setup section, select Use an existing project and choose the project from the list.
  • In the Functions Setup section, select the language as JavaScript, and enable ESLint.
  • When prompted to install dependencies, choose yes.

You might see a message saying “ high severity vulnerabilities”, but just ignore them. This is shown as Firebase CLI uses node.js 8 by default.

Also, node.js 8 is deprecated now, and they will stop supporting it on Firebase soon.

But in order to use node.js 10, you will need to upgrade your Firebase project to their Blaze Plan. So, we will be using node.js 8 for our project, but the same cloud function will also work while using node.js 10.

This completes the Firebase initialization. You will now see some new files created inside your root project directory.

Navigate to the functions > index.js present inside your root project directory. Here, you can define the cloud function.

We just need to update the presence and last_seen field of the Cloud Firestore according to the value present in the Realtime Database. You can achieve that as follows:

Now, you can deploy this Cloud Function by running:

firebase deploy

Upon successful deployment, this will get triggered as soon as the user presence status changes in the Realtime Database.

Conclusion

Cloud Functions makes it a lot easier to run backend code in an effectively serverless environment. You can trigger them using other Firebase services or directly using an HTTP request. Using Cloud Functions and Realtime Database, user presence can be tracked and updated seamlessly on Cloud Firestore.

References

Originally published on Codemagic Blog.

--

--

Souvik Biswas
Flutter Community

Mobile Developer (Android, iOS & Flutter) | Technical Writer (FlutterFlow) | IoT Enthusiast | Avid video game player