FCM Notifications with 26+

Firebase cloud messaging is a cross-platform messaging solution from which one can notify clients about new emails and engage users with the App at no cost. This blog assumes that you have linked firebase to your android project.

Let’s begin with the prerequisites:

  • Update or install the latest version of Android Studio 
  • Targets API level 16 and above 
  • Uses gradle 4.1 and higher
  • Uses Jetpack (AndroidX)

Concerning receiving fCM messages, the app should write a service which is implementing the FirebaseMessagingService.

class MyFirebaseMessagingService: FirebaseMessagingService() {}

FCM uses tokens that are encrypted, are in alphanumeric form and are unique for a device. These tokens are generated when the user launches the app for the first time, or when it clears the app’s data, or when it deletes the token. 

The FCM service will be triggered when the token changes for your device or generated for the first time. To work with the new token, one has to override onNewToken of FirebaseMessagingservice.

class MyFirebaseMessagingService: FirebaseMessagingService() {

  override fun onNewToken(fcmToken: String ? ) {
    super.onNewToken(fcmToken)
    Log.d("FCMToken", fcmToken)
  }

}

One has to register the service in the android manifest file and must include internet permission.

< service
android: exported = "false"
android: name = ".notifications.MyFirebaseMessagingService"
android: stopWithTask = "false" > <intent - filter > <action android: name = "com.google.firebase.MESSAGING_EVENT" / ></intent-filter>
</service >

<uses - permission android: name = "android.permission.INTERNET" / >

<uses - permission android: name ="android.permission.ACCESS_NETWORK_STATE" / >

For API 26 and above, notification channel is required which allows users to modify it from device notification settings. It should be named as:

private const val DEFAULT_NOTIFICATION_CHANNEL = "default_notification_channel"

The notification channel is pertinent to API 26 above and therefore include the below statement in your code:

private fun buildNotificationChannel() {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

}
}

And this is how you can achieve a notification channel:

val notificationChannel = NotificationChannel(DEFAULT_NOTIFICATION_CHANNEL, "My Default Notifications", NotificationManager.IMPORTANCE_HIGH)
// Configure the notification channel.
notificationChannel.description = "Default Channel"
notificationChannel.enableVibration(true)
notificationChannel.vibrationPattern = longArrayOf(0, 1000, 500, 1000)
notificationManager.createNotificationChannel(notificationChannel)

When a message is sent, onMessageReceived method of FirebaseMessagingService is triggered. For API 26+ add the following code inside the onMessageReceived method to handle the message received.

notificationBuilder = NotificationCompat.Builder(this,
DEFAULT_NOTIFICATION_CHANNEL)
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker("Hearty365")
.setContentTitle(notification.title)
.setContentText(notification.body)
.setSound(soundUri)

For devices below API level 26:

notificationBuilder = NotificationCompat.Builder(this)
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker("Hearty365")
.setContentTitle(notification.title)
.setContentText(notification.body)
.setSound(soundUri)
.setContentIntent(pendingIntent)

Overall code covering all the API levels will look like:

private fun sendNotification(notification: RemoteMessage.Notification) {
val notificationBuilder:NotificationCompat.Builder
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationBuilder = NotificationCompat.Builder(this, RECEPTION_NOTIFICATION_CHANNEL)
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText(notification.body)
.setSound(soundUri)
} else {
notificationBuilder = NotificationCompat.Builder(this)
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText(notification.body)
.setSound(soundUri)
.setContentIntent(pendingIntent)
}
notificationManager.notify(/*notification id*/1, notificationBuilder.build());
}

One should check the API level of the device to choose an appropriate way to work with the notifications. Once the channel is passed to the notification manager, it is now in control of the user to modify its channels through settings, like setting for sound, priority, colour, etc. For code on how to create a channel considering Android 8 and above example, follow the link: https://github.com/android/user-interface-samples/tree/main/Notifications

This is how one can achieve FCM notification for API  26+. For testing purposes use firebase platform to send text messages which can be specific to the user(specific to the token), or to a group of devices. For more information refer to the link https://firebase.google.com/docs/cloud-messaging/android/client.

Leave a Reply