Flutter Firebase Chat App – Part 3: Push Notifications for New Messages

Learn how to implement push notifications for new chat messages in Flutter using Firebase Cloud Messaging and Cloud Functions. Complete production-ready setup guide.

Introduction

In the previous article, we implemented real-time messaging using Firestore streams. Messages appear instantly when both users have the chat screen open.

However, if the receiver is not inside the chat screen or the app is closed, we need push notifications to alert them.

In this article we will implement:

  • FCM token storage
  • Cloud Function trigger for new messages
  • Sending push notifications
  • Handling notification clicks in Flutter

Chat Notification Architecture

User A sends message
       ↓
Firestore message document created
       ↓
Cloud Function trigger
       ↓
Fetch receiver FCM token
       ↓
Send push notification
       ↓
User B receives notification

Step 1: Add Firebase Messaging Package

dependencies:
  firebase_messaging: latest_version

Request Notification Permission

FirebaseMessaging messaging = FirebaseMessaging.instance;

await messaging.requestPermission(
  alert: true,
  badge: true,
  sound: true,
);

Step 2: Get FCM Token

String? token = await FirebaseMessaging.instance.getToken();
print("FCM Token: $token");

Store this token in the user document.

await FirebaseFirestore.instance
  .collection("users")
  .doc(userId)
  .update({
    "fcmToken": token
  });

Step 3: Cloud Function Trigger

exports.sendMessageNotification =
functions.firestore
.document('conversations/{conversationId}/messages/{messageId}')
.onCreate(async (snapshot, context) => {

  const message = snapshot.data();

  const receiverId = message.receiverId;

  const userDoc = await admin
    .firestore()
    .collection('users')
    .doc(receiverId)
    .get();

  const token = userDoc.data().fcmToken;

  await admin.messaging().send({
    token: token,
    notification: {
      title: "New Message",
      body: message.text
    }
  });

});

Deploy Function

firebase deploy --only functions

Handle Foreground Notifications

FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  print("New message received");
});

Handle Notification Click

FirebaseMessaging.onMessageOpenedApp.listen(
  (RemoteMessage message) {
    String conversationId =
      message.data['conversationId'];

    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (_) => ChatScreen(conversationId),
      ),
    );
  },
);

Send Data Payload with Notification

await admin.messaging().send({
  token: token,
  notification: {
    title: "New Message",
    body: message.text
  },
  data: {
    conversationId: context.params.conversationId
  }
});

Prevent Notification Spam

  • Do not notify sender
  • Check if receiver is already inside chat

Production Optimization

  • Batch notifications if many users
  • Use topics for group chats
  • Handle token refresh

Token Refresh Listener

FirebaseMessaging.instance.onTokenRefresh.listen((newToken) {
  print("Updated token: $newToken");
});

Security Best Practices

  • Never expose server keys
  • Send notifications only via backend
  • Validate user permissions

Testing Notifications

  • Send test notification from Firebase Console
  • Check Cloud Function logs

Production Flow Summary

Message sent
     ↓
Firestore write
     ↓
Cloud Function trigger
     ↓
Fetch receiver FCM token
     ↓
Send notification
     ↓
User opens chat from notification

Conclusion

Push notifications are essential for real-time communication apps. By combining Firestore triggers with Firebase Cloud Messaging, we can deliver instant alerts when new messages arrive.

In Part 4, we will implement: Chat Conversation List Screen (Recent Chats + Unread Count).

Share

What's Your Reaction?

Like Like 0
Dislike Dislike 0
Love Love 0
Funny Funny 0
Angry Angry 0
Sad Sad 0
Wow Wow 0