How to Implement Push Notifications in Flutter: A Simple Guide
Push notifications are one of the best ways to keep users informed and engaged. They help you send updates, reminders, and special offers even when the app is not open. This makes them very useful for improving user interaction and retention.
In this guide, I’ll show you how I added push notifications to a Flutter app using Firebase Cloud Messaging (FCM). I’ll explain how to set up Firebase, handle notification permissions, and send notifications to users. By the end of this tutorial, push notifications will be working in your own app.
Push notifications work even better when they are combined with Flutter in-app notifications, where users can see and manage all their notifications inside the app. If you also want to build an in-app notification center, check out my guide on Flutter in-app notifications to complete your notification system.
I’ve kept everything simple and easy to understand. Even if you’re new to Flutter or Firebase, you can follow along without any trouble. Each step is explained clearly, so let’s get started.
Table of Contents
Introduction to Push Notifications
What Are Push Notifications?
Why Should You Use Push Notifications in Your Flutter App?
Step 1: Add Required Dependencies
Add Firebase and Notification Packages to
pubspec.yamlInstall the Dependencies Using
flutter pub get
Step 2: Configure Firebase Cloud Messaging (FCM)
Setting Up Firebase for Android
Setting Up Firebase for iOS
Add Firebase API Keys and Configure FCM
Step 3: Initialize Firebase and Push Notifications
Initialize Firebase in Your Flutter App
Set Up Firebase Messaging for Push Notifications
Step 4: Create a Notification Service
What is the NotificationService Class?
Set Up Firebase Messaging in NotificationService
Add Local Notifications to Handle Foreground Messages
Step 5: Handle Notification Permissions
Requesting Notification Permissions for iOS and Android
Managing Device Tokens for Push Notifications
Step 6: Sending Push Notifications
How to Send Push Notifications to Your App
Backend Setup for Sending Push Notifications Using Firebase
Step 7: Testing Push Notifications
Testing Push Notifications in the Foreground
Testing Push Notifications in the Background
Testing Push Notifications When the App Is Killed
Summary of Push Notification Implementation
What You Can Do Next (Advanced Features)
Frequently Asked Questions (FAQs)
How Do I Handle Push Notifications When the App Is Closed?
How Can I Customize the Push Notification Appearance?
How Can I Test Push Notifications on Real Devices?
Introduction to Push Notifications
Push notifications are a powerful tool for keeping users connected with your app, even when they’re not actively using it. But what exactly are they, and why should you use them in your Flutter app? Let’s break it down.
What Are Push Notifications?
Push notifications are messages sent from a server to a user’s device, alerting them to important updates, news, or actions they need to take. They show up as banners, alerts, or pop-ups on the device, even if the app isn’t open.
These messages can be simple text, images, or interactive elements, and can be delivered directly to the lock screen or notification center. For a detailed guide on enhancing them with images, buttons, and custom actions, check out our customize notifications article. For example, when you get a new message on a chat app or a weather alert, that’s a push notification.
Why Should You Use Push Notifications in Your Flutter App?
Push notifications are essential for increasing user engagement and retention. Here are some reasons why they’re so effective:
Instant Communication: You can send real-time updates or alerts, keeping users informed instantly.
User Retention: By sending timely, personalized notifications, you can encourage users to open the app more often and continue using it.
Better User Experience: Push notifications help improve the overall user experience by providing relevant information right when users need it.
Marketing and Promotion: They can be used to promote new content, special offers, or upcoming events, increasing your app’s visibility and user interaction.
In short, push notifications are an easy and effective way to keep your app relevant and engaging, making sure users stay connected even when they’re not actively using it.
If you’re looking to learn about implementing different widgets in Flutter, you might want to check out Flutter Wrap Widget Explained with Code Examples. It will give you an in-depth look at how to utilize the Wrap widget for responsive design, an essential component for creating dynamic layouts.
Another helpful resource is How to Use Material Icons in Flutter, where we explore how to make your app more interactive and visually appealing with material design icons.
Project Setup Overview
Before diving into the code, let’s first set up the project and make sure we have everything we need for implementing push notifications. I’ll walk you through how I set up my Flutter project and the tools I used for this process.
Setting Up the Project
To get started, you’ll need to create a new Flutter project or use an existing one. If you’re starting fresh, here’s a simple way to create a Flutter app:
Create a new Flutter project:
flutter create push_notification_app
cd push_notification_app
Open the project in your preferred editor, like VS Code or Android Studio, and make sure everything is set up to run on both Android and iOS.
Install the necessary plugins to handle notifications and Firebase:
Add the dependencies to the
pubspec.yamlfile (we’ll cover this in detail in the next step).
Once your project is set up, you’ll be ready to configure Firebase and start integrating the notification system.
Tools and Libraries Required for Push Notifications
To handle push notifications, we’ll use two key tools:
Firebase Cloud Messaging (FCM)
Firebase Cloud Messaging (FCM) is a service that allows you to send push notifications to devices. It’s simple to integrate with Flutter and provides robust features to manage notifications, such as handling background notifications, customizing messages, and targeting specific user segments.Why use FCM?
It’s free, reliable, and integrates well with Firebase services.
It supports both foreground and background notifications.
It allows sending targeted notifications to specific users or groups.
flutter_local_notifications
This library helps you display notifications locally on the user’s device. While FCM handles receiving push notifications,flutter_local_notificationswill handle showing the notification when the app is in the foreground.Why use flutter_local_notifications?
It provides full control over the appearance and behavior of notifications.
It can handle notifications while your app is in the foreground, even when there’s no internet connection.
You can customize notification sounds, images, and more.
In the next steps, we’ll install and configure these libraries in your Flutter project to get push notifications up and running!
Step 1: Add Required Dependencies
To get started with push notifications, we need to add a few dependencies to our project. These dependencies will allow us to use Firebase Cloud Messaging (FCM) to send push notifications and flutter_local_notifications to display them.
Add Firebase and Notification Packages to pubspec.yaml
First, you need to open your pubspec.yaml file. This file contains all the dependencies for your Flutter project. We’ll add the necessary dependencies for Firebase Cloud Messaging and flutter_local_notifications.
Here’s what you need to add under the dependencies: section:
dependencies:
flutter:
sdk: flutter# Firebase pluginsfirebase_core: ^2.30.0
firebase_messaging: ^14.7.10
# Local notificationsflutter_local_notifications: ^17.0.0
firebase_core: This is needed to initialize Firebase in your Flutter project.firebase_messaging: This will allow us to handle push notifications.flutter_local_notifications: This will help us display notifications locally on the device, especially when the app is in the foreground.
Once you’ve added these dependencies, save the file.
Install the Dependencies Using flutter pub get
Now that we’ve added the required dependencies, it’s time to install them. You can do this by running the following command in your terminal or command prompt:
flutter pub get
This command will download and install all the packages you’ve added in the pubspec.yaml file. After this, you’ll be ready to move on to setting up Firebase and configuring notifications in the next steps.
If you run into any issues during installation, check that your internet connection is stable and ensure that the version numbers are correct. You can always visit pub.dev to find the latest versions of each package.
With the dependencies installed, we’re all set to move forward!
Step 2: Configure Firebase Cloud Messaging (FCM)
Now that we’ve set up the project and added the necessary dependencies, the next step is to configure Firebase Cloud Messaging (FCM) for both Android and iOS. Firebase is the backbone for sending push notifications, and we’ll need to set it up properly on both platforms to make everything work seamlessly.
Setting Up Firebase for Android
Create a Firebase Project:
Go to the Firebase Console.
Click on Add project and follow the steps to create a new Firebase project.
Add Android App to Firebase:
In the Firebase Console, click on Add App and select Android.
Enter your app’s Android package name (you can find it in your
AndroidManifest.xmlfile underpackage="com.example.yourapp").Register your app in Firebase and download the
google-services.jsonfile.
Add
google-services.jsonto your Flutter project:Move the downloaded
google-services.jsonfile to theandroid/appdirectory of your Flutter project.
Update
android/build.gradle:Open
android/build.gradleand add the following classpath inside thedependenciesblock:
classpath 'com.google.gms:google-services:4.4.0'
Update
android/app/build.gradle:In
android/app/build.gradle, at the bottom, apply the Google services plugin:
apply plugin: 'com.google.gms.google-services'
Add Permissions to
AndroidManifest.xml:In
android/app/src/main/AndroidManifest.xml, add the following permission:
<uses-permission android:name="android.permission.INTERNET" />
If you’re targeting Android 13+, you may also need to add the permission to post notifications:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
With these steps, your Android app is now set up to receive push notifications via FCM.
Setting Up Firebase for iOS
Add iOS App to Firebase:
In the Firebase Console, go to your project and click on Add App and select iOS.
Enter your iOS bundle ID (this can be found in Xcode under the General tab of your project settings).
Follow the steps to download the
GoogleService-Info.plistfile.
Add
GoogleService-Info.plistto your Flutter project:Move the
GoogleService-Info.plistfile into theios/Runnerdirectory of your Flutter project.
Configure iOS Permissions:
Open your
ios/Runner/Info.plistfile and add the following permission keys:
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>firebase_messaging_auto_init_enabled</key>
<false/>
Update
Podfile:Make sure your
ios/Podfilehas a platform version of at least iOS 10:
platform :ios, '10.0'
Install CocoaPods:
Run the following command to install the necessary CocoaPods dependencies:
cd ios
pod install
cd ..
This completes the setup for iOS, enabling Firebase Cloud Messaging to work with your Flutter app.
Add Firebase API Keys and Configure FCM
Obtain Firebase API Keys:
Firebase automatically generates an API key when you set up your project. You’ll find it in the Firebase Console under Project Settings.
You’ll need these API keys for configuring Firebase in your Flutter app, but you don’t need to manually add them. Firebase SDKs handle that automatically.
Firebase Initialization in
main.dart:Now, let’s initialize Firebase in your Flutter app. Open
main.dartand initialize Firebase before running the app. Here’s how I did it:
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'app.dart';// your app's entry point
void main()async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();// Initialize Firebase
runApp(MyApp());
}
Set Up Firebase Messaging:
After Firebase is initialized, you’ll need to configure Firebase Messaging in your
NotificationServiceclass (or equivalent) to handle incoming push notifications.
import ‘package:firebase_messaging/firebase_messaging.dart’;
FirebaseMessaging messaging = FirebaseMessaging.instance;
void setupPushNotifications() async {
// Request permission on iOS
await messaging.requestPermission();// Get the device token for push notifications
String? token = await messaging.getToken();
print(“Device Token: $token”);// Handle foreground messages
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print(‘Received a foreground message: ${message.notification?.title}’);
});
}
Now, Firebase Cloud Messaging (FCM) is set up for both Android and iOS, and Firebase is initialized properly in your Flutter app.
With these steps completed, you can start handling push notifications in your app, whether the app is in the foreground, background, or even terminated. Let’s move on to the next step—handling notifications in your app!
Step 3: Initialize Firebase and Push Notifications
Now that Firebase is set up for both Android and iOS, the next step is to initialize Firebase and set up Firebase Messaging in your Flutter app to handle push notifications. This step is crucial because it connects your app to Firebase and prepares it to receive notifications.
Make sure your app can reliably handle internet connectivity when initializing notifications, as unstable connections may cause delays or failures in receiving messages. For a complete guide on managing connectivity in Flutter, read the guide on Internet Connectivity checker in Flutter.
Initialize Firebase in Your Flutter App
To start using Firebase in your Flutter app, the first thing you need to do is initialize Firebase in the main.dart file. This ensures that Firebase is ready to be used when the app starts.
Here’s how you can initialize Firebase:
Import the Firebase Core package at the top of your
main.dartfile:import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'app.dart'; // your app's entry point file
Initialize Firebase in the
main()function using theFirebase.initializeApp()method. This should be done before running the app so that Firebase is fully initialized.void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize Firebase
await Firebase.initializeApp();
runApp(MyApp()); // Run your app after Firebase initialization
}
By calling await Firebase.initializeApp();, we ensure that Firebase is set up and ready to handle notifications or any other Firebase services (like authentication, Firestore, etc.).
Set Up Firebase Messaging for Push Notifications
Once Firebase is initialized, it’s time to set up Firebase Messaging so that your app can receive push notifications.
Here’s how you can set up Firebase Messaging for push notifications:
Import the Firebase Messaging package in the file where you will handle notifications (typically in a service or controller class):
import 'package:firebase_messaging/firebase_messaging.dart';
Create an instance of FirebaseMessaging:
FirebaseMessaging messaging = FirebaseMessaging.instance;
Request notification permissions (this is required for iOS). Even though permissions are usually requested automatically on iOS, you should handle them manually for a better user experience:
Future<void> requestPermissions() async {
// iOS-specific permission request
NotificationSettings settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
print('User granted permission: ${settings.authorizationStatus}');
}
For Android, permissions are handled automatically by Firebase, so you don’t need to request them explicitly.
Get the device token (unique identifier for each device) which is used to send notifications to specific devices:
Future<String?> getDeviceToken() async {
String? token = await messaging.getToken();
print("Device Token: $token");
return token;
}
This device token will be used to send targeted push notifications from Firebase to this specific device.
Handle background messages: Firebase provides a way to handle notifications when the app is in the background or terminated. To handle background notifications, you need to set up a background message handler.
In your main.dart or a separate file, add the following code:
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// This will be triggered when the app is in the background or terminated
print('Handling a background message: ${message.notification?.title}');
}Handle notifications when the app is in the foreground:
You can set up a listener to handle incoming push notifications while the app is active (in the foreground). Firebase provides an event listener for this:
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Received a foreground message: ${message.notification?.title}');
// You can show a local notification here using flutter_local_notifications
});
With Firebase Messaging properly initialized, your app is now set up to receive push notifications. The next step is to handle how to display the notifications when they arrive, whether the app is in the foreground or background, and how to manage them within your app.
In the next section, we will look at setting up local notifications to show messages when the app is active and receiving notifications in the foreground.
Step 4: Create a Notification Service
To manage push notifications effectively, it’s a good practice to separate the notification-related logic into its own service class. In this step, we’ll create a NotificationService class that will handle all aspects of push notifications, including receiving messages, handling background tasks, and showing local notifications when the app is in the foreground.
What is the NotificationService Class?
The NotificationService class is where all the notification-related functionality is managed. It acts as a centralized place for setting up push notifications, handling incoming messages, and managing how and when notifications are displayed. By separating this logic into a service class, we can keep the rest of our app clean and focused on its core functionality.
In this class, we’ll:
Set up Firebase Messaging to handle push notifications.
Set up local notifications using the
flutter_local_notificationspackage to show notifications when the app is in the foreground.Manage the registration of device tokens for sending push notifications.
Here’s a basic structure of how the NotificationService class might look:
class NotificationService {
static final NotificationService _instance = NotificationService._internal();
factory NotificationService() => _instance;
NotificationService._internal();
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// Initialize Firebase and notification services
Future<void> init() async {
// Request permissions for iOS
await _requestPermissions();
// Initialize local notifications
await _initLocalNotifications();
// Set up Firebase messaging
await _setupFirebaseMessaging();
}
// Request permissions on iOS
Future<void> _requestPermissions() async {
NotificationSettings settings = await _firebaseMessaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
print('Notification permissions: ${settings.authorizationStatus}');
}
}This class will handle initialization, permission requests, and set up the actual notification handling functionality.
Set Up Firebase Messaging in NotificationService
Now let’s set up Firebase Messaging to receive and handle push notifications. We’ll configure it in our NotificationService class.
Get the device token: This token is unique to each device, and it’s required for sending targeted push notifications. We’ll fetch and store this token to be used later.
// You can save this token to your backend or Firestore if neededFuture<void> _getDeviceToken() async {
String? token = await _firebaseMessaging.getToken();
print("Device Token: $token");
}Set up the message handler for foreground notifications: When the app is in the foreground, we can handle incoming messages by listening for them and showing a local notification if needed.
Future<void> _setupFirebaseMessaging() async {
// Handle foreground messages
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
print('Received a message in the foreground: ${message.notification?.title}');
// Call method to show local notification
await _showLocalNotification(message);
});
// Handle messages when the app is opened from a terminated state
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('Notification clicked!');
// You can handle navigation to a specific screen here if needed
});
// Handle background messages
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
}In this setup:
We use
FirebaseMessaging.onMessageto listen for push notifications when the app is in the foreground.When a message is received, we pass it to the method that handles showing local notifications (
_showLocalNotification).
Add Local Notifications to Handle Foreground Messages
When the app is in the foreground and a push notification is received, Firebase Messaging doesn’t automatically display the notification. This is where the flutter_local_notifications package comes in. We will use it to show the notification locally.
Initialize
flutter_local_notifications:First, initialize the plugin by setting up the notification settings for both Android and iOS.
Future<void> _initLocalNotifications() async { const AndroidInitializationSettings androidInitializationSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); const DarwinInitializationSettings iOSInitializationSettings = DarwinInitializationSettings(); const InitializationSettings initializationSettings = InitializationSettings( android: androidInitializationSettings, iOS: iOSInitializationSettings, ); await _flutterLocalNotificationsPlugin.initialize( initializationSettings, onDidReceiveNotificationResponse: (NotificationResponse response) { // Handle notification tap events print("Notification tapped: ${response.payload}"); }, ); }This code initializes the
flutter_local_notificationsplugin and sets up the necessary platform-specific initialization for both Android and iOS.Show Local Notification:
When a push notification is received in the foreground, we show a local notification using the following code:
Future<void> _showLocalNotification(RemoteMessage message) async { final notificationDetails = NotificationDetails( android: AndroidNotificationDetails( 'high_importance_channel', 'High Importance Notifications', importance: Importance.high, priority: Priority.high, ), iOS: DarwinNotificationDetails(), ); await _flutterLocalNotificationsPlugin.show( 0, // Notification ID message.notification?.title, message.notification?.body, notificationDetails, payload: message.data.toString(), ); }Here:
show()is the method that actually displays the notification.We pass the notification title and body from the incoming message.
The
payloadcan contain additional data that you can use to navigate to specific parts of the app when the notification is tapped.
By now, we’ve set up the core of the notification handling:
Firebase Messaging to handle the reception of push notifications.
Local notifications to show messages when the app is in the foreground.
We’ve also prepared the app to handle background notifications and notification taps.
The NotificationService class is now capable of handling all aspects of push notifications, from receiving messages to displaying them locally. In the next step, we’ll look at how to handle background notifications and integrate them with the app’s user interface.
Step 5: Handle Notification Permissions
Before your app can start receiving push notifications, you need to ensure that you request the necessary permissions from the user. On iOS, this step is mandatory, but Android handles permissions differently. Let’s look at how to request notification permissions for both platforms and manage the device tokens that Firebase uses to send push notifications.
Requesting Notification Permissions for iOS and Android
iOS: Requesting Permission
On iOS, you need to explicitly ask users for permission to send push notifications. This is done using the firebase_messaging package, which provides an easy way to request these permissions.
Here’s how to do it:
Request permission when the app starts or at a suitable point in your app’s flow:
print(‘User granted permission: ${settings.authorizationStatus}’);Future<void> requestPermissions() async {
NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
alert: true,
badge: true,
sound: true,
);
}alert: Allow the app to display alerts.
badge: Allow the app to update the badge icon on the app.
sound: Allow the app to play sounds when a notification arrives.
iOS-specific Setup: Make sure your
Info.plistfile is configured to enable background fetch and remote notifications:<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
Android: Permissions
For Android, permissions are handled automatically by Firebase Cloud Messaging (FCM). Android doesn’t require explicit permission requests for notifications (except for Android 13+). You just need to ensure that the necessary permissions are added to your AndroidManifest.xml file.
For Android 13 (API level 33) and higher, you’ll need to add the POST_NOTIFICATIONS permission:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
This will allow your app to send push notifications, but only on devices running Android 13 or higher. For earlier Android versions, the permissions are granted automatically.
Managing Device Tokens for Push Notifications
Every device that receives push notifications needs a device token (a unique identifier for the device). Firebase generates this token and uses it to target specific devices when sending notifications.
Get the device token: You can retrieve the device token using the
firebase_messagingpackage. Here’s how:Future<String?> getDeviceToken() async {
String? token = await FirebaseMessaging.instance.getToken();
print("Device Token: $token");
return token;
}
This token can then be saved to your backend (Firestore, for example), so you can target this specific device for future notifications.
Handle token refresh: Firebase automatically refreshes the device token from time to time. You should listen for token refreshes to keep your records updated:
FirebaseMessaging.instance.onTokenRefresh.listen((newToken) {
print("New Device Token: $newToken");
// Save the new token to your backend
});
Now, the device token is ready to be used for sending push notifications.
Step 6: Sending Push Notifications
With everything set up to receive notifications, the next step is sending push notifications to your app. There are two main parts to this process: sending push notifications from Firebase and configuring the backend to trigger these notifications.
How to Send Push Notifications to Your App
To send push notifications to your Flutter app, you can use Firebase Cloud Messaging (FCM). FCM is integrated with Firebase, and sending notifications is straightforward.
Send notifications using the Firebase Console:
Go to the Firebase Console.
In your project, navigate to Cloud Messaging.
Click Send your first message.
Fill in the notification title, body, and other options.
Select your target device by entering the device token you obtained earlier.
Click Send to deliver the notification to your app.
Send notifications programmatically (via the backend):
You can also send push notifications from your server by calling Firebase’s Cloud Messaging API. You’ll need to use an HTTP request with the Firebase server key.
Here’s an example of a simple HTTP request to send a push notification to a device token:
POST https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key=<YOUR_SERVER_KEY>
{
"to": "<DEVICE_TOKEN>",
"notification": {
"title": "Hello from Firebase!",
"body": "This is a test push notification."
},
"priority": "high"
}
Make sure to replace <YOUR_SERVER_KEY> with your Firebase server key, which you can find in the Firebase Console under Project Settings > Cloud Messaging.
Backend Setup for Sending Push Notifications Using Firebase
To send notifications programmatically, you’ll typically need to set up a backend that can send notifications to users based on certain triggers (e.g., new messages, promotions, etc.).
Here’s how you can set up a basic backend to send push notifications:
Create a Firebase Cloud Function to send notifications automatically when certain events happen (e.g., when a new message is posted or when an item goes live).
Example of a Cloud Function that sends notifications to users:
const admin = require('firebase-admin'); admin.initializeApp(); exports.sendPushNotification = functions.firestore .document('messages/{messageId}') .onCreate(async (snap, context) => { const messageData = snap.data(); const userToken = messageData.userToken; // Get the device token from Firestore const payload = { notification: { title: 'New Message', body: messageData.text, }, }; try { await admin.messaging().sendToDevice(userToken, payload); console.log('Notification sent successfully'); } catch (error) { console.error('Error sending notification: ', error); } });Deploy the Cloud Function:
Run
firebase deploy --only functionsto deploy the function to Firebase.
Trigger the Notification: Whenever a new message is created in the Firestore collection
messages, the function will be triggered and send a push notification to the user’s device.
Now, you’re ready to send notifications from Firebase to your app, either manually via the Firebase Console or programmatically from your backend using Cloud Functions.
This sets up the core system for sending and receiving push notifications. Next, we’ll explore how to handle the UI aspects, including customizing the notification display and testing the notification flow.
Step 7: Testing Push Notifications
Once you’ve set everything up, it’s time to test your push notifications. Testing ensures that notifications are delivered correctly and behave as expected across different scenarios. You’ll need to test notifications when the app is in the foreground, background, and even when it’s terminated (killed).
Let’s walk through how to test push notifications in each of these scenarios.
Testing Push Notifications in the Foreground
When the app is in the foreground (i.e., the user is actively using it), push notifications will not be shown as system alerts automatically. Instead, they will be handled by the app itself, allowing you to display custom notifications or update the UI as needed.
Here’s how to test push notifications in the foreground:
Set up a listener to handle foreground notifications. This is done using
FirebaseMessaging.onMessage.listen():FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
print("Received a foreground message: ${message.notification?.title}");
// Here, you can show a local notification using flutter_local_notifications
_showLocalNotification(message);
});
Trigger a push notification:
You can send a test notification from the Firebase Console or programmatically via your backend using FCM.
When the app is in the foreground, the notification should be received by the listener and can be displayed as a local notification.
Expected Behavior:
The push notification will trigger the callback you set up for the foreground.
You can customize how it’s shown (e.g., displaying a local notification or updating the app’s UI).
Testing Push Notifications in the Background
When the app is in the background (i.e., not actively in use but still open), push notifications should be received by the system and displayed in the notification tray. Users will see the notification as a banner or alert.
Here’s how to test push notifications in the background:
Send a push notification:
Send a notification from the Firebase Console or your backend.
Ensure the app is running in the background (e.g., minimized or in the app switcher).
Expected Behavior:
The notification should appear in the system’s notification tray.
When the user taps on the notification, the app should be opened, and any payload (like a deep link or data) should be passed to your app.
Handle the notification tap:
To handle what happens when a notification is tapped while the app is in the background, you can listen for the event usingFirebaseMessaging.onMessageOpenedApp:FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print("App opened from background via notification: ${message.notification?.title}");
// Navigate to a specific screen or perform any other action
});
Testing Push Notifications When the App Is Killed
When the app is killed (i.e., completely closed, not running in the background), push notifications will be delivered by the system and shown as usual. However, if the user taps on the notification, it should open the app and trigger the appropriate handler.
Here’s how to test push notifications when the app is killed:
Send a push notification:
Send a test notification from the Firebase Console or backend.
Ensure the app is completely killed (not running in the background or minimized).
Expected Behavior:
The notification should be delivered to the device.
When the user taps the notification, the app should launch and trigger the handler for the notification tap (via
FirebaseMessaging.getInitialMessage()):
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
if (message != null) {
print("App opened from terminated state: ${message.notification?.title}");
// Handle the message and navigate to a specific screen
}
});
Test both Android and iOS:
Push notifications behave slightly differently on iOS and Android, especially when the app is killed. Make sure to test on both platforms to ensure consistent behavior.
For iOS, you may need to enable background fetch and remote notifications (this is handled earlier in the setup), so it’s important to test on a real device, as simulators can behave differently.
Tips for Testing Push Notifications:
Use Real Devices: Push notifications often behave differently on simulators/emulators and real devices. Always test on a physical device for accurate results.
Check for Errors: Use the Firebase Console’s notification logs or check the logs in Xcode or Android Studio for any errors if the notifications aren’t showing as expected.
Test Various Scenarios: Make sure to test all scenarios — foreground, background, and killed app — to ensure notifications work properly in each state.
By following these steps, you’ll be able to thoroughly test your push notifications in different app states and ensure they work as expected. Once you’ve confirmed everything is working, you can confidently roll out the push notification feature to your users.
Conclusion & Next Steps
Implementing push notifications in Flutter using Firebase Cloud Messaging (FCM) is an essential feature for enhancing user engagement and ensuring your app remains connected with your users, even when they are not actively using it. We’ve walked through setting up Firebase, requesting permissions, managing device tokens, and sending push notifications to your app.
Summary of Push Notification Implementation
In this guide, we covered all the essential steps needed to implement push notifications in Flutter:
Setting Up Firebase: We configured Firebase for both Android and iOS to handle notifications using Firebase Cloud Messaging.
Handling Permissions: We ensured proper permissions were requested on both Android and iOS for receiving push notifications.
Firebase Messaging Setup: We set up Firebase Messaging to handle push notifications and manage device tokens.
Notification Service: We created a
NotificationServiceclass to centralize notification logic and handle notifications when the app is in the foreground.Testing: We tested push notifications across different app states (foreground, background, and terminated) to ensure they worked smoothly.
What You Can Do Next (Advanced Features)
Now that you have push notifications set up in your app, there are several advanced features you can explore:
Rich Notifications: Add images, buttons, or custom actions to notifications to make them more engaging and interactive.
Notification Channels: For Android 8.0 and above, set up notification channels to group notifications by priority or type.
Personalized Notifications: Use Firebase to send personalized notifications based on user data, like sending special offers or updates to specific user segments.
Scheduled Notifications: Send notifications at specific times or after a delay (e.g., reminders for users to take action).
Analytics: Use Firebase Analytics to track notification opens and user interactions, helping you optimize your notification strategy.
By exploring these advanced features, you can further enhance the user experience and increase user engagement with your app.
Frequently Asked Questions (FAQs)
Q1. How Do I Handle Push Notifications When the App Is Closed?
When your app is closed or terminated, push notifications will still be delivered by the system. However, tapping the notification will open the app, and the app will receive the notification data via getInitialMessage().
Here’s how to handle it:
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
if (message != null) {
// Handle the notification and navigate to a specific screen
print("App opened from closed state: ${message.notification?.title}");
}
});
This allows you to process the notification when the user taps it and navigate to the appropriate screen.
Q2. How Can I Customize the Push Notification Appearance?
To customize the appearance of push notifications, you can modify the notification details in the flutter_local_notifications plugin. This allows you to change the title, body, sound, icon, and more. For example:
final notificationDetails = NotificationDetails( android: AndroidNotificationDetails( 'channel_id', 'Channel Name', importance: Importance.high, priority: Priority.high, icon: 'launch_background', // Custom icon for Android notifications color: Colors.blue, // Set color for notification ), ); await flutterLocalNotificationsPlugin.show( 0, // Notification ID message.notification?.title, message.notification?.body, notificationDetails, );
You can also add actions, custom sounds, images, and badges to make your notifications more interactive and engaging for users.
Q3. How Can I Test Push Notifications on Real Devices?
To test push notifications on real devices, follow these steps:
Ensure Firebase is correctly set up on your project and that the correct device token is retrieved.
Send a push notification via the Firebase Console or programmatically from your backend to the device’s token.
Check the real device to ensure the notification appears as expected.
Test across platforms: Make sure to test on both Android and iOS devices, as push notifications may behave differently on each platform, especially when the app is in the background or terminated.
For reliable testing, always use a physical device instead of an emulator or simulator. Testing on a real device ensures accurate results, as notifications might behave differently in a simulated environment.



