Introduction
I built a WhatsApp clone with Flutter and Firebase in a few hours. Here is what I came up with.
There are a ton of messaging apps available. Some well-known players are WhatsApp, Threema, Signal, and others. Apart from a messaging functionality, they provide many other features like group chats, file transmission, or data backup. In my little experiment, I tried to recreate the messaging feature that all apps use. My requirements were the following:
- Two parties can send messages to each other
- The user interface should look similar to other messaging apps
- The client app is written with Flutter
- The backend is Google Firebase
User management
I created basic data models in the beginning. They contain all the information that is relevant to the messaging system. First, we have a ChatUser
object. It has an identifier, a name, and a list of chat identifiers. Why chat identifier? I’ll get to that later.
For authentication, I went with Firebase Authentication and its email/password authentication combination. It’s easy to implement and ensures that only registered users can write to my database. Uncontrolled data access can lead to huge bills! If you want even more security for your backend, try Firebase App Check!
The first screen is the login/register screen. The entire authentication is handled by Firebase Authentication. At no point, I can see the password! Chatting just requires a name that is displayed to other parties and an identifier to find the correct ChatUser
object.
Here is the code to log in and register. In both cases, the Firestore collection users
is accessed. During login, the matching ChatUser
object is grabbed while during registration, the ChatUser
object is created.
Want More Flutter Content?
Join my bi-weekly newsletter that delivers small Flutter portions right in your inbox. A title, an abstract, a link, and you decide if you want to dive in!
This is how the users
collection looks like in Firebase Firestore. The user identifier is also the document identifier which makes it easier to add filter clauses to the Firestore query. If I want to find a user with a certain id, I can look for the document with that id.
Listing and creating chats
After the login, the chat overview is loaded. It contains all chats and a button to start a new chat.
A Chat
object is pretty simple, it contains an identifier, a list of ChatUser
objects, and a list of ChatMessage
objects. The identifier is the concatenation of the identifiers of the users. And this chat identifier is also stored in each ChatUser
object.
When a new chat is created, then a new entry is added to the chats
collection in Firestore. Also, the ChatUser
objects are updated because their chat identifier collection gets a new entry.
When a User
logs in and arrives at the chat overview, I use the list of chat identifiers that is stored alongside a User
object to create streams. These streams update immediately and the user can see the latest message of every chat in the overview. I don’t want to load the entire chat message history yet but only the stream for fast updates. That’s why I decided to store chat identifiers with a User
.
Writing messages
Writing messages is pretty easy since we have all the information we need. The SingleChatPage
is attached to the stream of the chat collection with the given identifier. You can use a StreamBuilder widget for that purpose. It also takes care to dispose of the stream for you.
Adding a new message is reduced to adding a new message entry to the Chat
object. First, I create it from the Firestore collection. Then, I add a new entry. And last but not least, I call the update
method of Firestore to publish the changes.
Since the UI is attached to the chat stream, it reflects changes in an instant. Below you can see a screenshot of what it looks like:
Level up your Firebase skills!
Check out my free email course on Firebase fundamentals, and grab your copy of my Firebase ebooks. Start building amazing apps with Firebase today!
What does it look like?
Here is a video of the final example. In the background, you can see the database. I am writing messages from the app on my phone and have another instance running in the browser (left area of the video). As you can see, the chat is immediately updated when the database field is updated.
The next steps would be to add further functionality, eliminate some bugs, and improve the UI. In general, it is similar to known chat apps but it looks like it is a prototype. However, the goal was to implement a WhatsApp clone with Firebase and not make it a feature-complete and production-ready mobile app for every platform.
Possible enhancements
Here are some improvements that can be implemented to make the app even more useful. I did not do it because it wasn’t on the agenda. Feel free to get inspired.
- File and image transfer
Sending images and files is a crucial part of every messenger app today. This app can be easily enhanced to support these features by using Firebase Storage.
- Profile pictures
At the moment, users can only select their username during the registration process. Other personalization features are not implemented right now. Firebase Storage is also a perfect solution for this purpose.
- Group chats
This is also a frequently used feature. By design, the app supports group chats. It’s just not possible to select more than one chat partner currently.
- Push notifications
Get notified when a new message was posted in a chat. A very useful feature that can be implemented in various ways. Firebase offers this capability, too. Here’s my full guide to implementing notifications:
- Paging
When a chat is opened, all messages are downloaded. This might get slow if the message numbers grow. With paging, the bottleneck can be fixed. Paging means that only the latest chunk of information is retrieved. Previous data will only be grabbed if explicitly requested.
- Sound notifications
Messengers come with sound notifications for new messages, file transfers, or incoming calls. This could be implemented by adding small audio files to the Flutter project and playing them at the right moments. I don’t suggest storing them in the cloud or accessing them through HTTP requests because the delay might be high in some cases.
Bugs
The code is not bug-free. For example, if you start a new chat and send a first message, the UI is not updated. This is because there is no stream yet to subscribe to. There are also some bugs with the navigation when creating a new chat.
As it was an experiment, I didn’t invest much time in improving the user experience. But that can easily be fixed by anyone.
Additional resources
Here are some additional resources about Firebase in case you want to dive deeper into the topic.
Firebase Cloud Functions
Your all-in-one toolbox to building serverless infrastructures in the cloud. Write once and scale to infinity!
Firebase Cloud Storage
Upload and download user-generated content like on a file system. Firebase Cloud Storage makes file handling simple!
Firebase Remote Config
Real-time feature toggles or A/B testing are typical use cases of Firebase Remote Config. Learn how to implement them now!
Firebase Console
Learn how to manage projects, apps, users, billing plans, and costs with step-by-step guides in the Firebase Console.
Firebase Cloud Firestore
Learn about Firebase Firestore and write mobile apps with the power of a modern and fast NoSQL database.
Firebase Authentication
Implement email/password authentication or use social providers like Google, Microsoft, and Facebook for your apps!
Firebase Hosting
Host your web apps, microservices, dynamic, and static content with this powerful yet simple solution from Firebase!
Conclusion
Creating a messaging app like WhatsApp with Flutter and Firebase was easier than I thought. In fact, I spent most of the time with the user interface and not with the messaging logic or the Firebase backend. And it was a lot of fun. Of course, it’s not suited for a large user base but the concepts are quite clear to anybody.
Source code
You can find the source code on GitHub. The repo contains the working app without the Firebase configuration. You need to create the account and link your app with it. Then you can reproduce all the results of this article.