In order to provide real-time notifications for web and Android users, we have decided to make use of the Firebase features in our web application, staffyourself. Using only two Firebase features, we have created real-time notifications for users: the Firebase Realtime database for web users , and Firebase Cloud Messaging for Android users.
Firebase Realtime Database
What the Firebase Realtime database provides us with is the ability to save, retrieve, and sync our data with our NoSQL cloud database. We can sync data across all clients in realtime. The Firebase Realtime Database is simply a cloud-hosted NoSQL database and the data is stored as a JSON and synchronized in realtime to every connected client. As such, it has different optimizations and functionality compared to a relational database.
Firebase enables developers to build a great real-time experience that can serve millions of users without compromising responsiveness. Because of this, it is important to keep in mind that a developer will need to structure data in the database depending on how the data will be accessed by users.
- Integrate the Firebase Realtime Database SDKs using the API key and Realtime Database URL
- Create Realtime Database References
- Set data and listen for changes
As stated on Firebase’s webpage, Firebase Notifications is a free service that enables targeted user notifications for mobile app developers. Built on Firebase Cloud Messaging (FCM) and the FCM SDK, Firebase Notifications provides an option for developers seeking a flexible notification platform that requires minimal coding effort to get started, and a graphical console for sending messages. Send notifications to all supported message targets. Firebase Cloud Messaging handles the routing and delivery to targeted devices.
In order to inform Android users of certain events, our app uses FCM firebase notifications. Even though every Android device can have a listener to Firebase’s Realtime Database, we have chosen to use FCM for the following reason: depending on the Firebase package chosen, there is a limit on simultaneous connections to the real-time database. Because of the mentioned reason, Android users are not additional clients connected to the real-time database, and all of the simultaneous connections are reserved for the web users.
Integration and implementation
The app architecture consists of the following:
- Frontend web application in EmberJS
- Backend API used by web and mobile applications done in Play Framework
- Android Mobile Application
Authenticate the server
The staffyourself backend application has accessed and authenticated with the Firebase Realtime Database using the Firebase Admin SDK. A server should be authenticated with Firebase, rather than signed in with a user account’s credentials as you would in a client app. Our backend is authenticated with a service account that identifies our staffyourself backend to Firebase; thus, after the initialization of the Firebase Admin SDK with the credentials for a service account for the Firebase project, that instance has complete read and write access to our project’s Realtime Database.
As suggested by the Firebase development team, building a properly structured database requires quite a bit of forethought. Most importantly, a developer needs to plan for how data is going to be saved and later retrieved to make that process as easy as possible. As previously mentioned, the Firebase Realtime Database data is stored as JSON objects, thus making it a cloud-hosted JSON tree. Unlike a SQL database, there are no tables or records. When you add data to the JSON tree, it becomes a node in the existing JSON structure with an associated key.
This article will explain the implementation of a database reference that is unique per user but represents the same notification event. It is the “pendingNotifications “ JSON node that is taken as an example. To be clear, not all users listen to the same pending notification database reference location from the database, but each user has their own database reference in the real-time database located under their own unique identifier.
On the frontend web app, attaching an asynchronous listener to a database reference makes the user aware of data stored in a Firebase Realtime Database. This attached listener will be triggered once for the initial state of the data and again anytime the data changes.
The Realtime Database has a root node – which contains the list of unique identifiers (JSON nodes) each of the users is subscribed to – in order to listen to the changed and updated events only for their database reference.
This means that only the user who has the unique identifier, i.e. 3958, will be updated on the data or any child nodes updated under JSON node “root/users/3958/pendingNotifications”. The “pendingNotifications” JSON node in the database contains the list of application events that the user has not seen.
This enables the backend app to inform the web user about new notifications and the user to receive that information in milliseconds.
When an action on the staffyourself app is triggered and is required to inform a user, the backend API app will send a push notification to the user’s Android devices, if any, and a new JSON object will be created and stored in the list of “pendingNotifications” located in the real-time database under only this user’s unique identifier – making it a notification that only this user will receive.
As already written above, the user logged in from the web has an asynchronous listener attached to the list of pending notifications, which will be triggered anytime data changes or gets updated in any way. So, when a new JSON object is stored, the user’s listener will be triggered and receive the data changed, allowing us to show the user the notification content on the web in realtime, asynchronously. In cases where the user makes an action on the web interface or even via the android device if the user has read the notification, the backend API app simply removes the JSON object of the particular notification from the list.
Structuring the data
The notification sent and saved in the real-time database contains the minimum set of data – not only saving the memory space of the real-time database but also keeping in mind that each user should listen to a small dataset since all of the data is retrieved when an update occurs. The structure of our real-time database avoids nesting data. The Firebase Realtime Database allows nesting data up to 32 levels deep; thus, a developer might be tempted to think that this should be the default structure. However, when one fetches data at a location in the database, all of the child nodes are retrieved. In addition, when you grant someone to read or write access at a node in your database, you also grant them access to all data under that node. Therefore, in practice, it’s best to keep your data structure as flat as possible.
Sending push notifications
An important point to remember is that, in order to send push notification to android mobile devices, we use Firebase Cloud Messaging. If a user has an android device, after an action that requires a user to be informed, a push notification is sent from our backend API application. At the same time, the real-time database is updated. So, even if the user is logged in on an Android mobile device and on the web, they will receive the same notification in realtime. If an iOS app were to be developed, it would be pretty simple to integrate, as Firebase Cloud Messaging has the iOS SDK and supports sending notifications to iOS devices.
Why we chose Firebase
The reason Firebase is chosen for real-time notification features at staffyourself is very simple: it is a “one-stop-shop” or “one-stop service”. Firebase not only has the support for push notifications for Android and iOS devices but also provides the use of the real-time database service. Firebase’s easy integration and the simple usage of its SDKs make it even more appealing for developers.