Having trouble with flutter firebase messaging migration ]: - firebase

Future<Map<String, dynamic>> sendAndRetrieveMessage({String thatToken, String bodyMessage, String titleMessage}) async {
print('\n$thatToken' + '\n$bodyMessage' + '\n$bodyMessage');
await firebaseMessaging.requestPermission(
sound: true,
badge: true,
alert: true,
provisional: false,
);
await http.post(
'https://fcm.googleapis.com/fcm/send',
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$serverToken',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{'body': 'this is a body', 'title': 'this is a title'},
'priority': 'high',
'data': <String, dynamic>{'click_action': 'FLUTTER_NOTIFICATION_CLICK', 'id': '1', 'status': 'done'},
'to': thatToken,
},
),
);
final Completer<Map<String, dynamic>> completer = Completer<Map<String, dynamic>>();
FirebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
completer.complete(message);
},
);
return completer.future;
}
Hello World! Code above is firebaseMessaging configuration code that I used before, and today, I'm finally trying migration to latest version, which is 8.0.0-dev.14 firebaseMessaging. And here I got tough issue to solve. Migration documentation says that '.configure()' is totally deleted and I have to use custom static methods for each cases. So, here comes the problem.
I could following substitution guides for other parts of migration from source code, but I cannot find out which exact code snippet is needed to perform same feature with code above. This is because I got only few ideas what those Completer or configuration are exactly doing. My fault.. ]:
So, I hope someone who have already got through these migration issues, especially the 'configure' method help me out. Lastly, code below is culprit with its error message. Thank you in advance [:
FirebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
completer.complete(message);
},
);
errorMessage for above snippet: error: The method 'configure' isn't defined for the type 'FirebaseMessaging'.

To migrate to Firebase messaging > 8.0.0 you can use initializeApp from Firebase core then add callbacks to the onMessage method of FirebaseMessaging
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
await Firebase.initializeApp();
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
completer.complete(message);
});
Source: https://firebase.flutter.dev/docs/migration/#plugin-changes

Related

Receiving notification in flutter with Firebase

Whenever I receive a notification in firebase flutter, the notification is sent, and appears at the status bar, but my onbackgroundmessage handler isn't called or any onMessage functions. Any help is greatly appreciated. I will provide any further information that is necessary.
main.dart
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
},
onBackgroundMessage: myBackgroundMessageHandler,
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
},
I'm not sure about your code, but try this way, which is the way in the FlutterFire docs:
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print("Handling a background message: ${message.messageId}");
}
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Got a message whilst in the foreground!');
//...
});
But remember also that this code not enough to run when the app terminated where you need further work to handle Android and iOS to receive them.
FlutterFire really helps, also the example there: https://firebase.flutter.dev/docs/messaging/overview
Ready to help if it's still not working.
I managed to get the notifications working. What I did was send the notification with only data and no notification.
e.g.
BEFORE:
{notification: {title: 'my title', body: 'my body'}, data: {'click_action': 'FLUTTER_NOTIFICATION_CLICK'}
NEW:
{data: {'click_action': 'FLUTTER_NOTIFICATION_CLICK', 'title': 'my title', 'body': 'my body'}}

Firebase messaging - Notifications are not sent when app is Closed or sleep in Flutter

I have built my app in flutter and I have implemented both LocalNotifications and FCM messaging.
this is my code:
final FirebaseMessaging firebaseMessaging = FirebaseMessaging();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
#override
void initState() {
super.initState();
registerNotification();
configLocalNotification();
}
void registerNotification() {
firebaseMessaging.requestNotificationPermissions();
firebaseMessaging.configure(onMessage: (Map<String, dynamic> message) {
print('onMessage: $message');
return ;
}, onResume: (Map<String, dynamic> message) {
print('onResume: $message');
return Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NotificationsScreen()));
},
onLaunch: (Map<String, dynamic> message) {
print('onLaunch: $message');
return;
});
firebaseMessaging.getToken().then((token) {
print('token: $token');
FirebaseFirestore.instance
.collection('Consultant')
.doc(firebaseUser.uid)
.update({'deviceToken': token});
}).catchError((err) {
//Fluttertoast.showToast(msg: err.message.toString());
});
}
Future selectNotification(String payload) async {
if (payload != null) {
debugPrint('notification payload: $payload');
}
await Navigator.push(
context,
MaterialPageRoute<void>(builder: (context) => NotificationsScreen(payload: payload,)),
);
}
void showNotification(message) async {
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
Platform.isAndroid
? 'it.wytex.vibeland_pro_app'
: 'it.wytex.vibeland_pro_app',
'Vibeland Pro',
'Vibeland Pro',
playSound: true,
enableVibration: true,
importance: Importance.max,
priority: Priority.high,
);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics);
print(message);
print(message['body'].toString());
print(json.encode(message));
await flutterLocalNotificationsPlugin.show(0, message['title'].toString(),
message['body'].toString(), platformChannelSpecifics,
payload: json.encode(message));
await flutterLocalNotificationsPlugin.show(
1, '📩 Hai ricevuto un messaggio 📩 ', 'Controlla subito le Tue notifiche 🔔🔔', platformChannelSpecifics,
payload: 'item x',
);
}
void configLocalNotification() {
var initializationSettingsAndroid =
new AndroidInitializationSettings('#mipmap/ic_launcher');
var initializationSettingsIOS = new IOSInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
var initializationSettings = new InitializationSettings(
android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
I have built a function in firebase to push some New collections as notifications.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
const fcm = admin.messaging();
exports.sendNotification = functions.firestore
.document("Notifications/{id}")
.onCreate((snapshot) => {
const name = snapshot.get("name");
const subject = snapshot.get("subject");
const token = snapshot.get("token");
const payload = {
notification: {
title: "" + name,
body: "" + subject,
sound: "default",
click_action: "FLUTTER_NOTIFICATION_CLICK",
},
};
return fcm.sendToDevice(token, payload);
});
the version of firebase_messaging: ^7.0.3 and flutter_local_notifications: ^4.0.1
at the moment I don't upgrade due to some conflict with dependencies.
In this way I got both notifications when an app is open I get Local notifications correctly and when an app is in foreground and background I get Firebasemessaging according to the new collection added into my firestore.
The problem now comes when I close the app or the app after some minutes starts to sleep...
I can't get any notifications
To start again to get notifications, I need to run again the app and wake the app.
This is a problem with my app because my Apps notifications are very important and users need to get them always.
As you can on the FlutterFire documentation, foreground and background notification are handled differently by the plugin, so there are 2 thing you need to fix in your app.
First you need to prepare your Cloud Function to send background notifications as well as foreground, and in order to to that, you need to prepare your json to not only have a notification but also a data field, as follows:
const payload = {
notification: {
title: "" + name,
body: "" + subject,
sound: "default",
},
data: {
click_action: "FLUTTER_NOTIFICATION_CLICK"
}
};
Second, you are going to need configure your firebaseMassaging to receive background messages, like this:
firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) {
print('onMessage: $message');
return ;
},
onResume: (Map<String, dynamic> message) {
print('onResume: $message');
return Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NotificationsScreen()));
},
onLaunch: (Map<String, dynamic> message) {
print('onLaunch: $message');
return;
},
onBackgroundMessage: myBackgroundMessageHandler
);
And finally you need to create a handler that will manually handle background messages, following the example in the documentation you can do something like this:
Future<void> myBackgroundMessageHandler(RemoteMessage message) async {
print("Handling a background message: ${message}");
}
Adding the Line:
onBackgroundMessage: myBackgroundMessageHandler
Future<void> myBackgroundMessageHandler(RemoteMessage message) async {
print("Handling a background message: ${message}");
}
I got these error:
Nexus, [10.03.21 16:59]
[ File : app-release.apk ]
Amore, [10.03.21 17:09]
java.lang.RuntimeException: Unable to create service io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService: java.lang.RuntimeException: PluginRegistrantCallback is not set.
at android.app.ActivityThread.handleCreateService(ActivityThread.java:4023)
at android.app.ActivityThread.access$1600(ActivityThread.java:224)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1903)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7562)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: java.lang.RuntimeException: PluginRegistrantCallback is not set.
at io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService.C(Unknown Source:70)
at io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService.onCreate(Unknown Source:40)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:4011)
... 8 more

Flutter FCM how to remove the token when user uninstall the app

I'm developing a Flutter app (using Firebase Firestore and FCM) that aims to send notifications to all devices where the user has signed in. When the user signs out from a device, the token will be removed from Firebase. I am looking for a solution to remove the token when user uninstall the app, and in a way, able to store/update the multiple device tokens for a single user without storing the token based on the android id.
What I am using for sending notification:
final FirebaseMessaging firebaseMessaging = FirebaseMessaging();
Future<Map<String, dynamic>> sendAndRetrieveMessage(context) async {
await firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(sound: true, badge: true, alert: true, provisional: false),
);
await http.post(
'https://fcm.googleapis.com/fcm/send',
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$server_token',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
'body': '${widget.content}',
'title': '${widget.title}',
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'status': 'done',
'body': '${widget.content}',
'title': '${widget.title}',
},
'registration_ids': user_tokens,
},
),
).then((http.Response response){
final int statusCode = response.statusCode;
print("RESPONSE BODY: " + response.body);
print("STATUS CODE: " + statusCode.toString());
if (statusCode < 200 || statusCode > 400 || response.body == null) {
throw new Exception("Error while fetching data");
}
});
final Completer<Map<String, dynamic>> completer =
Completer<Map<String, dynamic>>();
firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
completer.complete(message);
},
onLaunch: (Map<String, dynamic> message) async {
completer.complete(message);
},
onResume: (Map<String, dynamic> message) async {
completer.complete(message);
},
);
return completer.future;
}
I have tried these methods for my notification module:
Update signed-in token in Firebase, but updating only one string also means only sending to the latest signed-in device of the user ignoring the other devices
Subscribe user to user_id topic, but topics are limited to 5 per sending notification. My app needs to send to a list of specific users (undetermined by a common topic, but a set of multiple conditions) and I want to avoid using loops as the notification function needs to work simultaneously for all receiving users
Read HTTP response message to detect failed token, the response returns "NotRegistered" but the response does not return the specific failed token
I would like to know if this is doable in Flutter and if there are solutions/simpler methods for this problem. Thank you

Is it possible to implement notification grouping/bundling using FCM in Flutter?

I try to implement group notification like this android group notification and ios group notification. But I can't able to do it. I tried this flutter_local_notification plugin too. but this works only when app open. not working on foreground(onResume) and background.
void registerNotification() {
_fcm.configure(
onMessage: (Map<String, dynamic> message) {
return;
},
onResume: (Map<String, dynamic> message) {
return;
},
onLaunch: (Map<String, dynamic> message) {
return;
},
onBackgroundMessage: backgroundMessageHandler);
}
payload
const payload = {
notification: {
title: title,
body: message,
},
data: {
click_action: "FLUTTER_NOTIFICATION_CLICK",
sound: "default"
},
android: {
priority: "high",
collapse_key: userName,//tried to add collapse_key for group notification
},
apns: {
headers: {
"apns-priority": "5",
},
},
token:token,
};
SOLUTION
I saw the react-native answer for this, you have to do same thing using Flutter with firebase_messaging react native answer
If you want to submit a group, you need to subscribe to a topic, in the documentation that mentions it, you would no longer send a single token, but would instead subscribe to a topic and submit it to that topic.

How Should I access the data elements of the notification payload in flutter?

Below is the notification payload in cloud function for FCM notification in flutter application, I am not able figure out how to access the elements of the data:{} when the notification is received in flutter application
PAYLOAD
const payload = {
notification: {
title: `NOTIFICATION2 `,
body: contentMessage,
badge: '1',
sound: 'default'
},
data: {
click_action: 'FLUTTER_NOTIFICATION_CLICK',
notification2: notificationid2,
detail: detail,
senderAvatarURL: messageRecieverSenderAvatar,
category: 'default'
}
}
NOTIFICATION CODE
firebaseMessaging.configure(onMessage: (Map<String, dynamic> message) {
print('onMessage: $message');
Platform.isAndroid ? showNotification(message['notification']) : showNotification(message['aps']['alert']);
return;
}, onResume: (Map<String, dynamic> message) {
print('onResume: $message');
return;
}, onLaunch: (Map<String, dynamic> message) {
print('onLaunch: $message');
return;
});
you can use the below code to access data :
if (message.containsKey('data')) {
// Handle data message
final dynamic data = message['data'];
}
once you got the data map, you can parse it.
the package https://pub.dev/packages/firebase_messaging shows an example of handling data messages, check part with title
Define a TOP-LEVEL or STATIC function to handle background messages

Resources