Am getting a frustrating experience with firebase messaging on my flutter app as onBackgroundmessage is not getting triggered while app is in background after sending request. I would like to know why as this is a core feature my app needs.
Future initialize(context) async{
_firebaseMessaging.configure(
onBackgroundMessage: Platform.isIOS ? null:_myBackgroundMessageHandler,
);
}
Future<dynamic> _myBackgroundMessageHandler
(Map<String, dynamic> message) async {
print("onBackground Message called");
fetchRideInfoInBackground();
return Future<void>.value();
}
}
Notification Payload
const message = {
notification: {
title: 'New Incoming Request',
body: `New incoming ${service} request`,
},
data: { orderId: orderId },
android: {
ttl: 30,
priority: 'high',
notification: {
click_action: 'FLUTTER_NOTIFICATION_CLICK',
},
},
tokens: driversRegistrationToken,
};
I don't see the whole file, but I assume your _myBackgroundMessageHandler is not a top level function.
Make it top level or static, after that it should work.
Edit: example
Future<dynamic> _myBackgroundMessageHandler (Map<String, dynamic> message) async {
print("onBackground Message called");
fetchRideInfoInBackground();
return Future<void>.value();
}
class PushHandler {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
Future initialize(context) async{
_firebaseMessaging.configure(
onBackgroundMessage: Platform.isIOS ? null:_myBackgroundMessageHandler,
);
}
}
Related
Push Notification code.
I don't understand how to implement the new method of implementing a notification in flutter using firebase
import 'dart:io' show Platform;
import 'package:google_maps_flutter/google_maps_flutter.dart';
class PushNotificationService
{
final firebaseMessaging = FirebaseMessaging.instance;
Future initialize(context) async
{
firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
retrieveRideRequestInfo(getRideRequestId(message), context);
},
onLaunch: (Map<String, dynamic> message) async {
retrieveRideRequestInfo(getRideRequestId(message), context);
},
onResume: (Map<String, dynamic> message) async {
retrieveRideRequestInfo(getRideRequestId(message), context);
},
);
}
Seems like you are using the old method. Here is the updated version. Link for your references
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification notification = message.notification;
showNotification(notification);});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print("onMessageOpenedApp: $message");});
FirebaseMessaging.onBackgroundMessage((RemoteMessage message) {
print("onBackgroundMessage: $message");});
Future initialize(context) async {
FirebaseMessaging.instance.getNotificationSettings(
FirebaseMessaging.onMessage.listen((Map<String, dynamic> message)) async {
retrieveRideRequestInfo(getRideRequestId(message), context);
},
onLaunch: (Map<String, dynamic> message) async {
retrieveRideRequestInfo(getRideRequestId(message), context);
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
getRideRequestId(message);
retrieveRideRequestInfo(getRideRequestId(message), context);
},
);
}
Instead of on Message use :
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}');
}
});
for background message
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}");
}
void main() {
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyApp());
}
Note background message is handled in separate isolate if you are using firebase you have to initialise it first to use it.
Reference:
Foreground:https://firebase.flutter.dev/docs/messaging/usage#foreground-messages
Background:https://firebase.flutter.dev/docs/messaging/usage#background-messages
I have successfully setup background notifications and tested it using postman and all is good.
Now I need to access Provider.of(context) in my backgroundHandler which must be a static method where there is no context.
All I need to do is to perform an action according to the data in the background notification.
Here is my code for initializing FCM (I do it in Splash screen)
Future<void> initFcm() async {
_firebaseMessaging.configure(
onBackgroundMessage: myBackgroundMessageHandler,
onMessage: (msg) async {
print('this is ONMESSAGE $msg');
},
onLaunch: (msg) async {
print('ON LAUNCH');
},
onResume: (msg) async {
print('ON RESUME');
},
);
// For testing purposes print the Firebase Messaging token
deviceToken = await _firebaseMessaging.getToken();
print("FirebaseMessaging token: $deviceToken");
}
static Future<dynamic> myBackgroundMessageHandler(
Map<String, dynamic> message) async {
print(message);
if (message.containsKey('data')) {
// Handle data message
final dynamic data = message['data'];
final orderId = data['order_id'];
//THE PROBLEM IS THAT HERE I DON'T HAVE CONTEXT (coz static method)
Provider.of<Orders>(context, listen: false).setBackgroundStatus(orderId);
}
if (message.containsKey('notification')) {
// Handle notification message
final dynamic notification = message['notification'];
}
// Or do other work.
}
My question is how can I handle tasks in provider in my backgroundHandler which is a static method that doesn't have context?
In initState() of the _PushMessagingExampleState class in the example app for Flutter firebase_messaging 6.0.13, _firebaseMessaging.configure is called first, followed by _firebaseMessaging.requestNotificationPermissions.
However, in the firebase_messaging 6.0.13 API reference for the FirebaseMessaging class, the first thing it states is:
Your app should call requestNotificationPermissions first and then
register handlers for incoming messages with configure.
Which is correct?
I'm guessing the API reference is correct and the example app could be improved?
Technically it doesn't matter but I have it set up as request permissions first, then configure. As an example of a working app:
configureFcm() {
if (!isConfigured) {
if (Platform.isIOS) {
_fcm.onIosSettingsRegistered.listen((IosNotificationSettings data) {
});
_fcm.requestNotificationPermissions(IosNotificationSettings(sound: true, badge: true, alert: true));
}
_fcm.configure(
// in foreground
onMessage: (Map<String, dynamic> message) async {
_handleNotification(message);
},
// onBackgroundMessage: (Map<String, dynamic> message) async {
// print('on background message $message');
// },
// in background
onResume: (Map<String, dynamic> message) async {
_handleNotification(message);
},
// terminated
onLaunch: (Map<String, dynamic> message) async {
_handleNotification(message);
},
);
isConfigured = true;
}
}
I'm getting push notification using firebase messaging service in my flutter application.I need to redirect the app to specific activity when I clicks the notification. Could you people suggest some ideas please? Thanks in advance.
This is the code I tried.
var initializationSettingsAndroid = new AndroidInitializationSettings(
'#mipmap/ic_launcher'); // Notification Initialization for android
var initializationSettingsIOS = new IOSInitializationSettings(); // Notification Initialization for IOS
var initializationSettings = new InitializationSettings(
initializationSettingsAndroid,
initializationSettingsIOS); //Initialization done according to their platform
flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
flutterLocalNotificationsPlugin.initialize(initializationSettings);
firebaseMessaging
.configure( // handling notification while app is in foreground
onLaunch: (Map<String, dynamic> message) async {
print('onlaunch');
//navigateTo(message);
Navigator.push(context, new MaterialPageRoute(builder: (BuildContext context)=> new Credits()));
},
onResume: (Map<String, dynamic> message) async {
print('onmesage $message');
print('onResume');
// navigateTo(message);
Navigator.push(context, new MaterialPageRoute(builder: (BuildContext context)=> new Credits()));
},
onMessage: (Map<String, dynamic> message) async {
print('onmesage $message');
body = message['notification']['body'];
title = message['notification']['title'];
Timer(Duration(seconds: 1), (){});
showNotificationWithDefaultSound(message);
print("title: $title");
print("body: $body");
//print("${message['data']['screen']}");
//Navigator.of(context).pushNamed(message['data']['screen']);
},
);
//Permission for IOS
firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(
alert: true,
sound: true,
badge: true
)
);
firebaseMessaging.onIosSettingsRegistered.listen((
IosNotificationSettings settings) {
print("IOS");
});
//geting token from the app
firebaseMessaging.getToken().then((token) {
tokenId = token;
print(tokenId);
});
//
Firebase messaging object provide you a configure method in you have onMessage, onResume and onLaunch where you can run code of your will. For your requirement I believe you have to call new page/activity such that when your user clicks on notification (when app is terminated i.e not in foreground and background) it will launch that page instead of main page. Implement this code in initState() of the root page
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async{
Print('on message $message');
},
onResume: (Map<String, dynamic> message) async {
print('on resume $message');
},
onLaunch: (Map<String, dynamic> message) async {
print('on launch $message');
//Call your pageRoute here
},
);