Firebase FCM Data Message — Complete Guide
In this tutorial, you'll learn about Firebase FCM Data Message. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
The Problem
You send a notification from Firebase Console but onMessageReceived doesn't fire, or you send a data message but the notification doesn't show.
Wrong Approach ❌
class MyFcmService : FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
// Expecting this to fire for ALL messages
showNotification(message.notification?.title ?: "", message.notification?.body ?: "")
}
}
Output: onMessageReceived doesn't fire when the app is in the background with a notification payload.
Right Approach ✅
class MyFcmService : FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
// Check for data payload (always received)
val data = message.data
val title = data["title"] ?: message.notification?.title ?: "Message"
val body = data["body"] ?: message.notification?.body ?: ""
val type = data["type"] ?: "general"
// Show notification with data
showNotification(title, body, type)
// Handle special data actions
when (type) {
"new_message" -> handleNewMessage(data)
"call" -> handleIncomingCall(data)
"silent_update" -> performSilentUpdate(data)
}
}
// This also fires when app is in foreground for notification messages
// For background notifications, use a helper:
private fun createNotificationChannel() { /* ... */ }
private fun showNotification(title: String, body: String, type: String) {
val intent = Intent(this, MainActivity::class.java).apply {
putExtra("type", type)
flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TOP
}
val pendingIntent = PendingIntent.getActivity(this, type.hashCode(), intent, FLAG_IMMUTABLE)
val notification = NotificationCompat.Builder(this, FCM_CHANNEL_ID)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(this).notify(System.currentTimeMillis().toInt(), notification)
}
}
// For high-priority data messages (FCM priority: high)
// Send data-only messages from server (no notification payload)
// { "data": { "title": "...", "body": "..." }, "priority": "high" }
Output: onMessageReceived fires for all data messages. Foreground + background handling works.
Prevention
- Use data-only payloads for guaranteed
onMessageReceiveddelivery. - For notification + data combined, handle both payload types.
- Use
message.datafor custom payloads. - Set FCM priority to
highfor time-sensitive messages.
Common Mistakes with Firebase fcm message
- Using
foldlinstead offoldl'causing stack overflow on large lists - Forgetting
deriving (Show, Eq)on custom data types needed for debugging - Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro