How can I prevent to display FCM notification on Flutter app background? - firebase

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print('Handling a background message ${message.messageId}');
}
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
I can display background notifications with these snippet codes. But is there any way to not display some specific notification in the background?
For example I don't want to display notifications with data = {title = "call"}

from the sender device u have to send data only notification
await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'key=$serverKey',
},
body: jsonEncode(
<String, dynamic>{
'data': <String, dynamic>{
'id': '2',
'status': 'done'
},
'to': userToken,
"collapse_key": uid,
},
),
);

add conditions in your _firebaseMessagingBackgroundHandler like
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
if(message.data["title"]=="Call")
{
// show nothing
}
else
{
// show notifications
}
}

Related

Flutter push notification's with firebase

In my case, the notification only arrives on the device from which the new item in the list has been added, other users do not receive the notification. I would like other users to receive notifications. Currently I'm using the topic (the same case is with the device token).
Here is my code...
This is my function for post notification on firebase server:
Future postNotification() async {
final postUrl = 'https://fcm.googleapis.com/fcm/send';
final data = {
'to': '/topics/weather',
"collapse_key": "type_a",
"notification": {
"title": channel.name,
"body": channel.description,
},
};
final headers = {
'content-type': 'application/json',
'Authorization':
'key = myserverkey'
};
final response = await http.post(
Uri.parse(postUrl),
body: json.encode(data),
encoding: Encoding.getByName('utf-8'),
headers: headers,
);
print(response.statusCode);
}
For this global functions I get response status code 200 and everything look's fine, for topic name in this example I use weather.I call this function when adding a new element to the list.
This is my function for show notifications and I use this function in home screen of my app:
void showNotification() async {
flutterLocalNotificationsPlugin.show(
0,
channel.name,
channel.description,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
importance: Importance.high,
color: Colors.blue,
playSound: true,
icon: '#mipmap/ic_launcher',
),
),
);
}
This is how I call the show Notification function on the home page of my application:
#override
void didChangeDependencies() {
super.didChangeDependencies();
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification.android;
if (notification != null && android != null) {
final messageTitle = message.notification.body;
FirebaseMessaging.instance.subscribeToTopic('weather');
showNotification();
print(messageTitle);
}
});
}
Do I need an extra backend to make this work on other devices as well?

What are the contents of RemoteMessage of Firebase?

https://blog.logrocket.com/flutter-push-notifications-with-firebase-cloud-messaging/
// For handling the received notifications
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
// Parse the message received
PushNotification notification = PushNotification(
title: message.notification?.title,
body: message.notification?.body,
);
As we can see, notification is one field in RemoteMessage structure.
and here: https://pub.dev/packages/firebase_messaging/example
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}');
}
messageId is another field in RemoteMessage.
What other fields are in this RemoteMessage structure? I tried to find its API but failed.
Can we override it and fill our own fields?
Here is the structure of RemoteMessage. You can add your custom data to the data property of it.
const RemoteMessage(
{this.senderId,
this.category,
this.collapseKey,
this.contentAvailable = false,
this.data = const <String, dynamic>{},
this.from,
this.messageId,
this.messageType,
this.mutableContent = false,
this.notification,
this.sentTime,
this.threadId,
this.ttl});
A usual notification payload when send from the backend/cloud functions looks like this:
const payload = {
notification: {
title: title,
body: message,
},
data: {
uid,
},
webpush: {
notification: {
icon: photoURL,
},
},
android: {
notification: {
image: photoURL,
},
},
apns: {
payload: {
aps: {
"mutable-content": 1,
},
},
fcm_options: {
image: photoURL,
},
},
};

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

Firebase 'to' send to everyone in Flutter

Currently I have topics to send push notifications. In particular
all: this is a topic in which I send notifications to everyone
paid: this is a topic in which I send notification only to a small group of users
Today I was upgrading Flutter to the newest firebase package and I encountered this:
<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': await firebaseMessaging.getToken(),
},
But wait, isn't 'to' meant to send notifications only to a specific device? Why does
'to': await firebaseMessaging.getToken(),
this send a message to all devices? I am confused because the doc says that 'to' is for specific targets too. Thanks!
The to property in an FCM message determines where it is sent to. The value of the to property can be the device token of a single device, it can be the ID of a device group, or it can be a topic.
It sounds like in your actual code you pass a topic in to, while in the sample in your question it passes a device token.
you can use this Firestore api by google to send push notifications
Future<bool> callOnFcmApiSendPushNotifications(List <String> userToken) async
{
final postUrl = 'https://fcm.googleapis.com/fcm/send';
final data = {
"registration_ids" : userToken,
"collapse_key" : "type_a",
"notification" : {
"title": 'NewTextTitle',
"body" : 'NewTextBody',
}
};
final headers = {
'content-type': 'application/json',
'Authorization': constant.firebaseTokenAPIFCM // 'key=YOUR_SERVER_KEY'
};
final response = await http.post(postUrl,
body: json.encode(data),
encoding: Encoding.getByName('utf-8'),
headers: headers);
if (response.statusCode == 200) {
// on success do sth
print('test ok push CFM');
return true;
} else {
print(' CFM error');
// on failure do sth
return false;
}
}

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