Futter background notification with Navigation - flutter

i listen to the notification as below
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await FirebaseMessaging.instance.getToken();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyProject(
appRouter: AppRouting(),
));
}
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
NotificationServices ntService = NotificationServices();
print("Handling a background message: ${message.data['room']}");
ntService.showNotification(message);
}
void showNotification(RemoteMessage message) {
flutterLocalNotificationsPlugin.show(
message.data.hashCode,
message.data['title'],
message.data['body'],
NotificationDetails(
android: AndroidNotificationDetails(
NotificationServices.channel.id,
NotificationServices.channel.name,
channelDescription: NotificationServices.channel.description,
//channel.description,
icon: 'launch_background',
playSound: true,
// other properties...
),
),
payload: message.data['room']);
}
}
await flutterLocalNotificationsPlugin.initialize(
initialzationSettings,
onDidReceiveNotificationResponse: onSelectNotification,
onDidReceiveBackgroundNotificationResponse: onSelectNotification,
);
in the onSelectNotification
i get the roomID and then navigate to it but to do so i had to but it in the homepage screen in order to set the user and room data so i get an error i should use in the top level function in the main.dart and it is working fine with the foreground notification but for the background it just open the app so any ideas of how should i do it

Related

firebaseMessagingBackgroundHandler not triggered when app is in background

I assumed I followed all the steps to handling background notifications from firebase in flutter. I have created a top-level function that I am expecting to be triggered whenever a notification comes in. However, the function is never triggered.
Here's the top-level background handler function that exists in my home page widget but outside the class:
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// ignore: avoid_print
print('A background message just showed up : ${message.messageId}');
// update SQLite
var result = await PageService.instance
.add(PageService.instance.convertToPage(message.data));
print('added to db: ${result}');
}
Here is my home page init state that calls a function to initialize firebase messgaging:
#override
void initState() {
super.initState();
_initializeFirebaseMessaging();
}
And then here is the _initializeFirebaseMessaging function that is defined in the home page class as well:
void _initializeFirebaseMessaging() {
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
print('new notification arrived');
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
// update SQLite
var result = await PageService.instance
.add(PageService.instance.convertToPage(message.data));
print('added to db: ${result}');
if (notification != null && android != null) {
// show notification
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
color: Colors.blue,
playSound: true,
icon: '#mipmap/ic_launcher',
),
));
}
});
}
The onmessage.listen works fine as I get notificationd and handle them while I'm in the app, but the background handler is not triggered at all.
I would appreciate any help!
You have to call FirebaseMessaging.onBackgroundMessage inside your main() not in initState()
try: after main func
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
...
}
and remove WidgetsFlutterBinding.ensureInitialized(); in firebaseMessagingBackgroundHandler
onMessage handles foreground notification
onMessageOpenedApp handles background notification
Instead of using onMessage for handling Background notifications, add another function block of FirebaseMessaging with onMessageOpenedApp, if you want notification while the app is in background, like this:
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message){...})
onMessage only works when the app is in foreground.
If you want notification while the app is in the terminated state you can use:
FirebaseMessaging.instance.getInitialMessage().then((message){...})
Update your firebaseMessagingBackgroundHandler to this:
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
// ignore: avoid_print
print('A background message just showed up : ${message.messageId}');
// update SQLite
var result = await PageService.instance
.add(PageService.instance.convertToPage(message.data));
print('added to db: ${result}');
}
And finally, the main() should look like this:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Add Firebase Initialization:
await Firebase.initializeApp();
// This will initialize a new Firebase instance.
// Background message handler
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
runApp(const App());
}
You should call FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); from within main(), not from Homepage initState(){}.

iOS firebase getInitialMessage not working Flutter

I installed firebase notification package in my Flutter project and setup the necessary settings for sending data.
Everything works fine on android, when the app is completely closed, when I send a parameter via firebase, the page I want opens, but on the ios part, when I click on the notification, it does not catch the click and the page I want does not open.
I would be very happy if you could help me where is the main point I should pay attention to for the ios part.
Main.dart
initialMessage = await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
if (initialMessage!.data['type'] == 'notification') {
await Future.delayed(const Duration(seconds: 4));
navigatorKey.currentState?.pushNamed(
'/notification'); // navigate to login, with null-aware check
}
}
pushNotificationService.dart
class PushNotificationService {
Future<void> setupInteractedMessage() async {
await Firebase.initializeApp();
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null &&
initialMessage.data['type'] == 'notification') {
await Future.delayed(const Duration(seconds: 6));
navigatorKey.currentState?.pushNamed(
'/notification'); // navigate to login, with null-aware check
}
// Also handle any interaction when the app is in the background via a
// Stream listener
// This function is called when the app is in the background and user clicks on the notification
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
// Get.toNamed(NOTIFICATIOINS_ROUTE);
print(message.toMap().toString());
print(message.data['type'].toString());
if (message.data['type'] == 'notification') {
navigatorKey.currentState?.pushNamed('/notification');
}
});
await enableIOSNotifications();
await registerNotificationListeners();
}
registerNotificationListeners() async {
AndroidNotificationChannel channel = androidNotificationChannel();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
var androidSettings =
const AndroidInitializationSettings('#mipmap/ic_launcher');
var iOSSettings = const IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,
);
var initSetttings =
InitializationSettings(android: androidSettings, iOS: iOSSettings);
flutterLocalNotificationsPlugin.initialize(initSetttings,
onSelectNotification: (message) async {
// This function handles the click in the notification when the app is in foreground
// Get.toNamed(NOTIFICATIOINS_ROUTE);
});
// onMessage is called when the app is in foreground and a notification is received
FirebaseMessaging.onMessage.listen((RemoteMessage? message) {
// Get.find<HomeController>().getNotificationsNumber();
print(message!.data['type'].toString());
print(message.toMap().toString());
if (message.data['type'] == 'notification') {
navigatorKey.currentState?.pushNamed('/notification');
}
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
// If `onMessage` is triggered with a notification, construct our own
// local notification to show to users using the created channel.
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
icon: android.smallIcon,
playSound: true,
),
),
);
}
});
}
enableIOSNotifications() async {
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
badge: true,
sound: true,
);
}
androidNotificationChannel() => const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
importance: Importance.max,
);
}
info.plist background modules
UIBackgroundModes
fetch
processing
remote-notification

FirebaseMessaging.instance.getInitialMessage() is not called in terminated state

FirebaseMessaging.instance.getInitialMessage() is not called in terminated state when we click notification that contains message data like this ,instead it is displaying screen from splash screen
{
"registration_ids": [
""
],
"data": {
"title": "Flutter9 Object Notification.3...",
"body": "this is flutter Data Object notification test message from",
"android_channel_id": "dgdgsdfgs",
},
"android":{
"priority":"high"
}
}
Given that you not displayed how you setup your fcm , here is how to go about it
/// Create a [AndroidNotificationChannel] for heads up notifications
late AndroidNotificationChannel channel;
/// Initialize the [FlutterLocalNotificationsPlugin] package.
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
/// To verify things are working, check out the native platform logs.
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
print('Handling a background message ${message.messageId}');
}
in main.dart
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
// setup displaying notifications
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title// description
importance: Importance.high,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
handle message call this in your initstate
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage? message) {
if (message != null) {
// do message things
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
showMessage(message: message);
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
),
iOS: IOSNotificationDetails(subtitle: notification.title)));
}
});
incase you need to navigate on receiving a message
void showMessage({required RemoteMessage message}) async {
if (message.data['route'] == "mypage") {
var myparams = message.data['payload'];
Navigator.of(context).push(MaterialPageRoute(
fullscreenDialog: true,
builder: (_) {
return MyPage(
params:myparams,
);
})); ...
With FCM, you can send two types of messages to clients:
Notification messages, are sometimes thought of as "display messages." These are handled by the FCM SDK automatically.
Data messages, which are handled by the client app. "
https://firebase.google.com/docs/cloud-messaging/concept-options
What you are trying to send is a data message, my best guess is that the firebase SDK does not recognize the data message so it does not trigger the firebase message event listener. Your notification must have a 'notification' field for firebase SDK to listen to.

How to display multiple notifications using flutter plugin : flutter_local_notifications

Here is my code below :
const AndroidNotificationChannel notificationChannel = AndroidNotificationChannel(
'high_importance_channel',
'high importance Notificaion',
'this channel is used for import notification',
importance: Importance.high,
playSound: true,
);
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
Future<void> firebaseBackgroundMessageHandler(RemoteMessage message) async {
await firebaseMessageHandler(message);
}
Future<void> firebaseForegroundMessageHandler(RemoteMessage message) async {
await firebaseMessageHandler(message);
}
Future<void> firebaseMessageHandler(RemoteMessage message) async {
await Firebase.initializeApp();
try {
flutterLocalNotificationsPlugin.show(
message.notification.hashCode,
message.data["title"].toString(),
message.data["body"].toString(),
NotificationDetails(
android: AndroidNotificationDetails(notificationChannel.id, notificationChannel.name, notificationChannel.description),
));
} catch (_err) {}
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(firebaseBackgroundMessageHandler);
FirebaseMessaging.onMessage.listen(firebaseForegroundMessageHandler);
//FirebaseMessaging.onMessageOpenedApp.listen(firebaseMessageHandler);
final AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('e_app');
final InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(notificationChannel);
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(alert: true, badge: true, sound: true);
}
The code is working fine for a single notification but whenever I send multiple notifications to android, it shows only the last notification in the status bar.
Could anyone help me about
how to show multiple notifications in the status bar using the flutter local notification plugin?
If you want to group your notifications, there is an option to do that in flutter_local_notifications.
To do this, you can add the following in your code
for ios : threadIdentifier in IOSNotificationDetails
for android : groupChannelId, groupChannelName, groupChannelDescription,
You can find these in the docs here: https://pub.dev/packages/flutter_local_notifications#displaying-a-notification under 'Grouping notifications'.
Basically notifications under same threadId or groupId will all be grouped and shown

Migrating Push notification from firebase_messaging 6 to firebase_messaging 10+

I am coming from an old Firebase_messaging plugin 6 + to the newer Firebase_messenger plugin 10 +, I am able to do most of the thing but can't get the message data, I want to convert this code from the older plugin to a newer one and use methods like configure launch and onResume.I can receive the push notifications, foreground and background information about the message but can't read it.
class _ChatScreenState extends State<ChatScreen> {
#override
void initState() {
super.initState();
final fbm = FirebaseMessaging();
fbm.requestNotificationPermissions();
fbm.configure(onMessage: (msg) {
print(msg);
return;
}, onLaunch: (msg) {
print(msg);
return;
}, onResume: (msg) {
print(msg);
return;
});
}
What I have done so far
Under AndroidManifest.xml added
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="high_importance_channel" />
On main.dart
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('Handling a background message ${message.messageId}');
}
Future <void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyApp());
}
Here is where I want to get the data from the server
class _ChatScreenState extends State<ChatScreen> {
#override
void initState() {
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage message) {
if (message != null) {
print(message);
}
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Got a message whilst in the foreground!');
print('Message data: ${message.data}');
if (message.notification != null) {
print(
'Message also contained a notification: ${message.notification}');
}
});
});
super.initState();
}
On Debug while the App is in the foreground
D/FLTFireMsgReceiver(15437): broadcast received for message
I/flutter (15437): Got a message whilst in the foreground!
I/flutter (15437): Message data: {}
I/flutter (15437): Message also contained a notification: Instance of 'RemoteNotification'
On Background
D/FLTFireMsgReceiver(15437): broadcast received for message
W/FirebaseMessaging(15437): Missing Default Notification Channel metadata in AndroidManifest. Default value will be used.
I/flutter (15437): Handling a background message 0:1624718321445677%ba7e1d8bba7e1d8b
Although the Notification Text and body is fine in the notification window but can't get the same info in the debug screen, it returns empty. Also is my implementation correct?
With a little bit of searching I believe the missing piece was flutter_local_notifications: ^5.0.0+4 The changes I have made in
main.dart
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
print('Handling a background message ${message.messageId}');
}
const AndroidNotificationChannel channel = const AndroidNotificationChannel(
//for notificaiton initialization
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
importance: Importance.high,
playSound: true,
);
//initialize plugin
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
//for background messaging
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
//Local Notification implementation
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
//for firebase plugin and messaging required
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true, badge: true, sound: true);
runApp(MyApp());
}
In the class where I want the notification
class _ChatScreenState extends State<ChatScreen> {
#override
void initState() {
//foreground messaging
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification notification = message
.notification; //assign two variables for remotenotification and android notification
AndroidNotification android = message.notification?.android;
if (notification != null && android != null) {
print(message);
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id, channel.name, channel.description,
color: Colors.blue,
playSound: true,
icon: '#mipmap/ic_launcher'),
),
);
print(notification.title);
print(notification.body);
}
});
//Do when the user taps the notification
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
//same as above
});
super.initState();
}
Would be nice if some one update this process for IOS as I don't have a developer Id to test it.