Skip to content

Firebase FCM Data Message — Complete Guide

DodaTech Updated 2026-06-24 2 min read

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 onMessageReceived delivery.
  • For notification + data combined, handle both payload types.
  • Use message.data for custom payloads.
  • Set FCM priority to high for time-sensitive messages.

Common Mistakes with Firebase fcm message

  1. Using foldl instead of foldl' causing stack overflow on large lists
  2. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  3. 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

### What is a data-only message?

A message with only data field (no notification field). These always trigger onMessageReceived regardless of app state. Notification messages with notification field skip onMessageReceived in background.

### Why does my notification show twice?

You're handling both message.notification (system shows it automatically) and your own showNotification(). Use data-only messages to control the display yourself.

### What is FCM priority?

normal priority waits for doze-friendly Windows. high priority delivers immediately. Use high for chat messages, calls, and time-sensitive alerts.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro