Collapsing FCM Notification? Like a pro!
After rambling through the web on “How to collapse FCM notifications of similar type”, I couldn’t really find any useful resource. Only thing I knew was that Firebase will send a collapse_key
in its RemoteMessage
which can be used to identify the notification type. I wanted to achieve something like this:
So, I took down all the requirements on a piece of paper:
- A datatype to handle something like one key : multiple values where key would be the
collapse_key
and values would be the Notification Ids. Possibly aHashMap<String, List<Integer>>
. - A mechanism to keep track of the notifications to collapse and save this data in some kind of cache.
I stumbled upon Guava’s Multimap
but if I were using it, the implementation would become Multimap
specific. So I ended up creating a wrapper class MultiValuedMap<String, Integer>
which fulfils my requirement.
Handling Notifications Elegantly 💫
I took inspiration from this very good article by Jovche Mitrejchevski that expounds on how to handle Android Notifications elegantly.
In this article, Jovche uses Dagger and the best practices to achieve the intended. Here’s the flow mentioned:
AppPushNotification
AppPushNotification is responsible for resolving PushNotificationItem. It also decides when to show/hide a notification.
The Code
The Methods
push()
: pushes a notification. Entails all the logic to resolve a PushNotificationItem, create a channel and show/hide the notification.createChannel()
: creates a notification channel based on theandroid_channel_id
and returns AppNotificationChannel. To know more about notification channels, see documentation.notify()
: notifies theNotificationManager
to show a notification.cancel()
: cancels a notification fromNotificationManger
for given id.
The Dependencies
- NotificationManager : Android class to show/hide notifications.
- NotificationItemResolver : resolves a notification based on the
android_channel_id
and returns a PushNotificationItem. - NotificationBuilder : builds a notification using NotificationCompat.Builder class.
- CollapsingNotificationManager : checks when notifications should collapse based on the recorded number of notifications of a type.
Collapsing Notifications Elegantly 💫
CollapsingNotificationManager is one of the dependencies injected in AppPushNotification which manages collapsing of notifications.
The Algorithm
- Notifications will collapse based on
collapse_key
fromRemoteMessage
. Ergo, you should be sending a payload with acollapse_key
. By default,collapse_key
is the app package name registered in Firebase. - When the first notification (of say
type_a
) is triggered, the usual notification will be shown. - When second notification (of say
type_a
) is triggered, it is added to the queue and if the size of this list oftype_a
notification is greater than 1, flagshouldCollapse
is set totrue
. - Hence, the previous notification is cleared and the collapsing text will be shown based on the type. In this case, it will be “You have 2 notifications of Type-A”.
- Similar steps will be followed for
type_b
notifications and so on. - When user taps on or dismisses this notification from Notification Tray, this list of
type_a
notifications cleared. MainActivity handles the tap whereas NotificationDismissTracker takes care of dismissal.
The Code
Writing functions was never this “fun”. Thanks to Kotlin :)
The Methods
getNotificationsToCollapse()
: returns theNOTIFICATION_IDS
to collapse so that the previous notification can be cleared if required.clearNotificationsToCollapse()
: clears theNOTIFICATION_IDS
to collapse of a particular type orNOTIFICATION_KEY
when :
a. The user taps on a particular notification (see MainActivity).
b. The user dismisses a notification (see NotificationDismissTracker) from the Notification Tray.
The Dependencies
- CollapsingNotificationStore : persists all the
NOTIFICATION_IDS
pertaining to a particular type orNOTIFICATION_KEY
, in this casecollapse_key
. It makes use of the PreferenceManager to get and put theCOLLAPSING_NOTIFICATIONS
ie. aMultiValuedMap<String, String>
.
Github Sample
There! We collapsed our notifications based on type. If this post made you happy, you can sing the Pharrell Williams song and clap along 👏🏻😊
Here is a blog to help you test notifications easily.
Special thanks to Jovche Mitrejchevski for the wonderful post, my friends and colleagues Arun Sasidharan for helping me create the flowcharts and Garima Jain for her valuable feedback 🙏🏻