Building chat app with Flutter and Firebase

Duy Tran
Flutter Community
Published in
7 min readAug 24, 2018

Major update:

Aug, 27th, 2022 — Upgrade dependencies and fix to work fine with Flutter 3

Jun, 4th, 2021 — Migrating to Flutter 2 and using Dart sound null safety

Oct, 2th, 2021 — Apply provider & restructure

In this article, we’ll try to build a simple chat app with Flutter and Firebase from scratch (including Firebase Auth, Google Sign-In, Cloud FireStore, and Firebase Storage). The app will have the following features:

  • Sign-in by Google account.
  • Chat 1–1 with other users (send text, image, sticker).
  • Update profile and avatar.
  • Push notification (refer to the extension article here)

Maybe some template code in this article is outdated, please check the source code for the latest.

TLDR: check source code at the end of this article.

Demo

1. Creating project on Firebase

Following this video to connect your flutter app to Firebase.

Note:

First, if you would like to use Google sign-in, need to do this step (only for Android — the video above won’t do it since he doesn’t use sign-in method) to get SHA-1 key (get the debug certificate is enough).

Second, add this line #import <Firebase/Firebase.h> to AppDelegate.h

Start the Cloud Firestore and Storage

Then enable sign-in method with Google

Now you’re done with this step, don’t need to add or init any data manually at Firebase.

Rules at Storage:

Use this mode for storage to accept only image file type

The rule check image file type only works for Android (iOS does always not match this condition even if you upload the image). Because the image upload on Android is image/jpeg or image.png… but on iOS is just application/octet-stream no matter what the file type is.

So you can temporarily remove the second condition or change it to

if true && (request.resource.contentType.matches('image/.*') || request.resource.contentType.matches('application/octet-stream'));

to pass iOS file type.

If anyone finds a better solution, please tell me.

Rules at Database:

And this mode for database

2. Installing plugins

Following these instructions to add firebase_auth, google_sign_in, cloud_firestore, firebase_storage to your project.

These plugins help login app by Google account, get user info, real-time database for chatting and upload image.

And the others will help us show toast, cache data local, pick images from gallery, cache network image and parse date time.

3. Layout the login page

When user login success, the return variable firebaseUser contains some user information, like displayName, photoUrl

then we’ll check if the user is new or not (by query to the server does this ID exist). If they’re a new user, write it to the database.

The other things we need to do here are writing user info to local storage (to use in other pages, mention later) and navigate to the main page when login successful.

For more details, please check out the source code at the end of this article, in the path lib/auth_provider.dart

4. Layout the home page

This page contains list all users in our database, we’ll show all the info we got like avatar, nickname and about me. If you would like to design user has more field than that, create a detail page to see all particular user info is a good idea.

Get list user quite simply by using StreamBuilder like below:

One more thing we have to do at this page is to create a option menu to go to Settings or Log out page. Our option menu will like this

About how to create option menu and dialog, please check my source code in the path lib/pages/home_page.dart

5. Layout the settings page

At here, the user can change some info like their avatar, nickname and about me. You can add more field than that if you want.

At first, we load current user info from disk (the data we wrote when they log in) to show on UI.

If user change avatar, we need to upload that file to Firebase Storage, then get file’s URL.

After that, update user info to Cloud Firestore with new photoUrl we just set.

Notice that one user just need one avatar, so we set file name is userID, if user uploads a new file, Firebase will replace the old with the new one.

More details, please check my source code in the path lib/pages/settings_page.dart

6. Layout the chat page

This is the core page so we have many things to do on it.

First, need to layout the UI, root widgets are like this

Need PopScope because we have to set chattingWith value to null when exit page (condition to trigger push notification)

Second is handle sticker and keyboard appearance, if keyboard being shown, the sticker will dismiss and vice versa.

Keyboard show, sticker hide and vice versa

We need a variable isShowSticker to detect should show sticker or not, focusNode help us control should focus on text input or not, if focusing, the keyboard will appear.

Third is load previous message and listening for new income message, we’ll use StreamBuilder

Notice that when user A (current user) chat with user B (peer user), the problem is which groupChatId we’ll use to read and write data chat to the server since conversation of A & B need to save at the same node? So my idea is hashing the A’ uid and B’ uid, then creates a string like this:

Then at user A or B, they both read and write data at the same Cloud Firestore node.

At the time of this article is published, I found no way to scroll item to bottom list programmatically when receive a new message, so my idea is reverse array message (set attribute .orderBy when query data from the server), then set reverse attribute in ListView to true. Then list message will have a good UX like other apps chat.

Fourth is handle sending messages, if user sends an image, we need to upload this image and get URL, then we just add the content of the message is this URL, and stickers (are saved at the local project) just need the name of the file is enough.

When receiving a new message, we’ll check type first, if the type is image, we load this image from network, if the type is sticker, show it from the local file.

More details, please check my source code in the path lib/pages/chat_page.dart

Cloud Firestore structure

Our database should be like this, just for refer if you need to.

Node users
Node messages

--

--