I’ve been working on integrating Firebase Cloud Messaging (FCM) with my Flutter app, and I’ve run into an issue where the onMessageOpenedApp method is not triggered when I click on a notification while the app is in the background or terminated.
Here’s my setup:
Main Dart File (main.dart)
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'my_app.dart';
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyApp());
}
Home Screen Dart File (home_screen.dart)
import 'package:flutter/material.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'firebase_messaging_service.dart';
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
FirebaseMessagingService notificationServices = FirebaseMessagingService();
@override
void initState() {
super.initState();
notificationServices.requestNotificationPermission();
notificationServices.foregroundMessage();
notificationServices.firebaseInit(context);
notificationServices.setupInteractMessage(context);
notificationServices.isTokenRefresh();
notificationServices.setupFirebase();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Screen'),
),
body: Center(
child: Text('Flutter Firebase Messaging Demo'),
),
);
}
}
Firebase Messaging Service Class (firebase_messaging_service.dart)
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'communication_view_model.dart';
class FirebaseMessagingService {
FirebaseMessaging messaging = FirebaseMessaging.instance;
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
void isTokenRefresh() async {
messaging.onTokenRefresh.listen((event) {
debugPrint("Token refreshed: $event");
});
}
Future<void> setupFirebase() async {
messaging.getToken().then((value) {
debugPrint("FCM Token: $value");
});
}
void initLocalNotifications(BuildContext context, RemoteMessage message) async {
var androidInitializationSettings = const AndroidInitializationSettings('@mipmap/ic_launcher');
var iosInitializationSettings = const DarwinInitializationSettings();
var initializationSettings = InitializationSettings(
android: androidInitializationSettings,
iOS: iosInitializationSettings,
);
await _flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: (response) {
handleMessage(context, message);
},
);
}
void firebaseInit(BuildContext context) {
FirebaseMessaging.onMessage.listen((message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (kDebugMode) {
print("Notification Title: ${notification?.title}");
print("Notification Body: ${notification?.body}");
print('Data: ${message.data}');
}
if (Platform.isIOS) {
foregroundMessage();
}
if (Platform.isAndroid) {
initLocalNotifications(context, message);
showNotification(message);
}
});
}
void requestNotificationPermission() async {
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: true,
badge: true,
carPlay: true,
criticalAlert: true,
provisional: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
if (kDebugMode) {
print('User granted permission');
}
} else if (settings.authorizationStatus == AuthorizationStatus.provisional) {
if (kDebugMode) {
print('User granted provisional permission');
}
} else {
if (kDebugMode) {
print('User denied permission');
}
}
}
Future<void> showNotification(RemoteMessage message) async {
AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel',
'High Importance Notifications',
description: 'This channel is used for important notifications.',
importance: Importance.max,
);
AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
importance: Importance.high,
priority: Priority.high,
icon: '@mipmap/ic_launcher',
);
const DarwinNotificationDetails darwinNotificationDetails = DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
);
NotificationDetails notificationDetails = NotificationDetails(
android: androidNotificationDetails,
iOS: darwinNotificationDetails,
);
Future.delayed(Duration.zero, () {
_flutterLocalNotificationsPlugin.show(
0,
message.notification?.title,
message.notification?.body,
notificationDetails,
);
});
}
Future<void> setupInteractMessage(BuildContext context) async {
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
if (message != null) {
print("Initial message received: ${message.data}");
handleMessage(context, message);
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print("onMessageOpenedApp triggered with message: ${message.data}");
handleMessage(context, message);
});
}
void handleMessage(BuildContext context, RemoteMessage message) {
// Handle the message
}
}
Android Manifest (AndroidManifest.xml)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.your.package">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:name="${applicationName}"
android:label="your_app_name"
android:icon="@mipmap/ic_launcher">
<meta-data android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_launcher"/>
<meta-data android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/green"/>
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="high_importance_channel"/>
<activity
android:name=".MainActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<service
android:name=".FirebaseService"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
</application>
</manifest>
Issue
I am receiving notifications when the app is in the background.
Clicking on the notification does not trigger the onMessageOpenedApp method.
What I’ve Tried
Verified that the notification payload includes click_action: "FLUTTER_NOTIFICATION_CLICK".
Added intent filter in AndroidManifest.xml for FLUTTER_NOTIFICATION_CLICK.
Initialized Firebase in main.dart and set up background message handler.
Used FlutterLocalNotificationsPlugin to show notifications.
Question
How can I ensure that onMessageOpenedApp is triggered when a notification is clicked while the app is in the background or terminated?
Any help would be greatly appreciated!