Flutter Firebase Cloud Messaging (FCM) Updated
Firebase Cloud Messaging (FCM) is a service that allows you to send notifications and messages to devices running your app. This tutorial will guide you through the setup and usage of FCM in Flutter to receive notifications when the app is in both the foreground and background.
We’ll go through:
- Setting up Firebase for your Flutter project.
- Integrating Firebase Cloud Messaging (FCM) into your Flutter app.
- Sending and receiving push notifications in both foreground and background states.
Prerequisites
- Firebase Configured Watch Here if you don’t know how
- A real device to test
1. Add Firebase SDK to Flutter
To use Firebase with Flutter, you need to add Firebase SDK dependencies to your project.
Open pubspec.yaml
and add the following dependencies:
dependencies:
flutter:
sdk: flutter
firebase_core: ^3.6.0
firebase_messaging: ^15.1.3
flutter_local_notifications: ^17.2.3
Install the dependencies:
flutter pub get
2. Initialize Firebase in Flutter
In the lib/main.dart
, initialize Firebase at the start of your app.
import 'package:fcm_test/services/notification_service.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await NotificationService.instance.initialize();
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Text('hello'),
),
),
);
}
}
3. Configure Firebase Messaging
In the services/notification_service.dart, copy this:
1. Background Message Handler
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await NotificationService.instance.setupFlutterNotifications();
await NotificationService.instance.showNotification(message);
}
- Purpose: This background handler processes notifications when the app is terminated or in the background.
- @pragma(‘vm’): Ensures that the function is available for background processing by the Dart VM, which is required for FCM background messages.
- Action: It calls
setupFlutterNotifications
to initialize notifications andshowNotification
to display the incoming message.
2. NotificationService Class Singleton
class NotificationService {
NotificationService._();
static final NotificationService instance = NotificationService._();
...
}
- Purpose: This class is a singleton, meaning only one instance exists throughout the app.
- Structure: Using the private constructor (
NotificationService._()
), we create an instance (NotificationService.instance
), which can be accessed anywhere in the app.
3. Firebase Messaging and Local Notifications Plugin
final _messaging = FirebaseMessaging.instance;
final _localNotifications = FlutterLocalNotificationsPlugin();
- These variables hold instances of
FirebaseMessaging
(to manage FCM) andFlutterLocalNotificationsPlugin
(for local notifications). - _messaging: Manages FCM tasks like getting tokens and handling messages.
- _localNotifications: Manages local notifications, which we use to display custom notifications on both Android and iOS.
4. Initialization Method
Future<void> initialize() async {
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await _requestPermission();
await _setupMessageHandlers();
final token = await _messaging.getToken();
print('FCM Token: $token');
}
- FirebaseMessaging.onBackgroundMessage: Registers the background handler to process messages when the app is not active.
- _requestPermission: Requests notification permissions from the user (iOS specific).
- _setupMessageHandlers: Sets up message handlers for handling notifications in different states.
- Get FCM Token: Retrieves the device’s FCM token, which is required to target notifications to specific devices.
5. Permission Request Method
Future<void> _requestPermission() async {
final settings = await _messaging.requestPermission(
alert: true,
badge: true,
sound: true,
provisional: false,
);
print('Permission status: ${settings.authorizationStatus}');
}
- Purpose: Requests notification permissions from the user, necessary for iOS.
- Options: Specifies types of notifications allowed (alerts, sounds, badges).
- Output: Logs the user’s authorization status (granted, denied, or provisional).
6. Setup Flutter Local Notifications
Future<void> setupFlutterNotifications() async {
if (_isFlutterLocalNotificationsInitialized) return;
...
_isFlutterLocalNotificationsInitialized = true;
}
- Purpose: Initializes local notifications only once.
- Android Configuration: Sets up an Android notification channel for high-importance notifications, which appear as alerts.
- iOS Configuration: Sets up iOS-specific notification settings, like alert presentation and sound.
- Initialization: Calls
_localNotifications.initialize
to activate notification settings and listeners.
7. Show Notification Method
Future<void> showNotification(RemoteMessage message) async {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
...
}
- Purpose: Displays a notification with data from an incoming FCM message.
- Message Processing: Checks if there’s a notification payload and displays it using
_localNotifications.show
. - Android & iOS: Creates notification details with custom settings for both platforms, such as icons and sound, and includes the message data as a payload.
8. Setup Message Handlers
Future<void> _setupMessageHandlers() async {
FirebaseMessaging.onMessage.listen((message) {
showNotification(message);
});
FirebaseMessaging.onMessageOpenedApp.listen(_handleBackgroundMessage);
final initialMessage = await _messaging.getInitialMessage();
if (initialMessage != null) {
_handleBackgroundMessage(initialMessage);
}
}
- Purpose: Sets up handlers to process notifications in different app states.
- Foreground Messages: Listens for notifications when the app is active (
onMessage
), displaying the notification locally. - Background & Terminated Messages: Handles notifications opened from the background or terminated state (
onMessageOpenedApp
andgetInitialMessage
).
9. Handle Background Message
void _handleBackgroundMessage(RemoteMessage message) {
if (message.data['type'] == 'chat') {
// open chat screen
}
}
- Purpose: Processes notifications when the app is launched from a notification.
- Example Action: If the message contains a specific type (e.g., “chat”), it can navigate to a specific screen or execute other logic.
4. Testing Push Notifications
You can now send test messages to your app using Firebase Cloud Messaging.
- Go to the Firebase Console.
- Navigate to Cloud Messaging.
- Click on New Notification.
- Enter the notification details and target the app via its FCM token.
- Click Send Message to trigger the push notification.
Make sure your app is either running in the foreground or background to observe the notifications.
Conclusion
In this tutorial, we covered the entire process of integrating Firebase Cloud Messaging into a Flutter app, handling foreground and background notifications, and configuring the required permissions and settings for both Android and iOS. You can now send notifications using Firebase and receive them on your device regardless of whether the app is open or closed.
If you enjoyed this tutorial and want to dive deeper, feel free to check out the GitHub Source complete code for this example.
Happy coding! 🎉