I'm building android app with firebase cloud messaging.
My app can receive message from FCM console.
However, it cannot receive from python, although the response is good.
Could you give me some advice?
class fbMessaging():
def __init__(self):
cred = credentials.Certificate('./env/firebase.json')
firebase_admin.initialize_app(cred)
def send_to_device(self, text, token):
message = messaging.Message(
data = {
'title': 'test',
'body': text,
},
token = token,
)
response = messaging.send(message)
return response
def main():
fm = fbMessaging()
res = fm.send_to_device('test', 'MY CORRECT TOKEN')
print(res)
onMessageRecieved is here
override fun onMessageReceived(message: RemoteMessage?) {
val from = message!!.from
val data = message.data
Log.d(TAG, "from:" + from!!)
Log.d(TAG, "data:$data")
}
Printed response is below.
projects/match-XXXXX/messages/0:1554291593xxxxxx%43f99108f9xxxxxx
Using Firebase Cloud Messaging, you can send Notification payload or Data payload or both.
Notification Payload contains
title - Notification Title
body - Notification body
The key names fixed and can't be changed.
Data Payload, on the other hand, is simply a key-value pair and you can send any key name with string type as its value.
FCM Behavior:
Based on whether the app is in the foreground or background and the existence of Notification payload or Data payload or both, the FCM message is received by different components in the app.
Handling of FCM notification as per documentation,
Notification messages delivered when your app is in the background. In this case, the notification is delivered to the device’s system tray. A user tap on a notification opens the app launcher by default.
Messages with both notification and data payload, when received in the background. In this case, the notification is delivered to the device’s system tray, and the data payload is delivered in the extras of the intent of your launcher Activity.
This behavior has been explained clearly in the Receive Messages Section.
As you can see, if only in the case where Notification payload is sent in standalone you don't have to build Notification UI. Otherwise, you have create the Notification UI when onMessageReceived is called.
Using Python:
Notification Payload Example:
message = messaging.Message(
notification=messaging.Notification(
title='This is a Notification Title',
body='This is a Notification Body',
),
token=registration_token,
)
Data Payload Example:
message = messaging.Message(
data={
'score': '850',
'time': '2:45',
},
token=registration_token,
Both:
message = messaging.Message(
notification=messaging.Notification(
title='This is a Notification Title',
body='This is a Notification Body',
),
data={
'score': '850',
'time': '2:45',
},
token=registration_token,
Related
I use Firebase Cloud Messaging (FCM) HTTP Legacy API protocol to send push notifications in JSON to android mobile devices. For the client side I use react-native-fcm library.
The aim is to send the notification to the particular devices when the application is in 3 states:
1) running
2) background running
3) killed
According to the documentation for FCM there are 3 different types of messages which can be sent via FCM service:
1) notification (has predefined fields)
2) data (set whatever fields you want)
3) mixed (notification + data).
The logic of listening the event for incoming message on the client side using react-native-fcm is the next:
this.notificationEmitterSubscription = FCM.on(FCMEvent.Notification, notif => {
if(notif && notif.fcm){
//received from Firebase
if(!notif.local_notification && notif.title){
let badge = parseInt(notif.badge);
FCM.setBadgeNumber(badge);
this.showNotification(notif.title, notif.body, badge);
}
//notification is clicked
if(notif.opened_from_tray){
FCM.setBadgeNumber(0);
this.executeNavigateAction(notif.fcm.action); //this method just navigates user to a particular screen in the application
}
}
});
Show notification method is implemented in this way:
showNotification(title, body, badge) {
FCM.presentLocalNotification({
body: body,
priority: "high",
title: title,
sound: "default",
large_icon: "ic_launcher",// Android only
icon: "ic_launcher",
show_in_foreground :true, /* notification when app is in foreground (local & remote)*/
vibrate: 300, /* Android only default: 300, no vibration if you pass null*/
lights: true, // Android only, LED blinking (default false)
badge: badge,
local: true,
click_action: NAV_SCREEN_NAME
});
}
notif.title, notif.body and notif.badge are the fields which are set in data section of the message when sending it via FCM API. In other word the message is sent in the (3) mixed form:
{
"registration_ids" : ["FCM_device_token_1", "FCM_device_token_2"],
"notification" :
{
"title" : "fcm notification message title",
"body" : "fcm notification message body",
"badge" : 111
},
"data" :
{
"title" : "fcm data message title",
"body" : "fcm data message body",
"badge" : 222
}
}
If the message is sent as (1) notification (without "data" section in the message, in this case some changes in the reading the fields are necessary, to change notif.title -> notif.fcm.title, but this is not the main point in the question) or mixed (3) then the listener for the notification is NOT triggered when application is (2) background running and (3) killed. As a result, the badge number is not set. BUT despite the fact that the method showNotification(title, body, badge) is not called (because the event listener is not triggered) the message IS shown. It seems that react-native-fcm has internal implementation for this situation to show (1) notification and (3) mixed messages automatically when application is not running. In other words, the listener IS called for (1) notification and (3) mixed messages only when the application is (1) running and IS NOT called when the application is in the (2) background or (3) killed and does NOT show the badge number. However, the message itself IS shown for all situations.
Another approach is to send a (2) data message. This type of FCM message triggers the listener (notificationEmitterSubscription) for all states of the application: (1) running and (2) background running and (3) killed. As a result, badge number is set in all these states. However, despite the fact that method showNotification(title, body, badge) is called whenever a data FCM message is received, method FCM.presentLocalNotification does NOT display the message if the application is killed.
Thus, in few words, I have a question.
How to:
EITHER display a badge number when (1) notification or (3) mixed message is received and the application is in (2) background running or (3) killed
OR display a (2) data message when the application is (3) killed?
Thank you!
The solution has been found. The statement is that: there is no code running if the application is killed, so the messages is handled and displayed out of your code. The message has to be set in the next format to be shown for the killed status:
{
"registration_ids" : ["FCM_token_1", "FCM_token_2"],
"data" :
{
"custom_notification" :
{
"title" : "FCM test title",
"body" : "FCM test body"
},
badge : 1
}
}
In your react-native application in the notification handler the notification is received as a json value of notif.custom_notification property. So, the code looks like this:
this.notificationEmitterSubscription = FCM.on(FCMEvent.Notification, notif => {
if(notif && notif.fcm){
//received from Firebase
if(!notif.local_notification && notif.custom_notification){
let message = JSON.parse(notif.custom_notification);
let body = message.body;
let title = message.title;
let badge = parseInt(notif.badge);
FCM.setBadgeNumber(badge);
this.showNotification(title, body, badge);
}
//notification is clicked
if(notif.opened_from_tray){
FCM.setBadgeNumber(0);
this.executeNavigateAction(notif.fcm.action);
}
}
});
The issue can be solved as a resolved one.
I have function in Firebase Cloud Functions which is used to send notifications to specific users within my app and has as the notificationContent the following code:
const notificationContent = {
notification: {
title: "My Notification Title",
body: "My Notification Body",
icon: "default",
sound : "default"
}
};
I have tried to use collapse_key: "unique_key" but it has no effect. I read the has an effect only when the device is offline. I also have used a tag: "unique" but every time a new notification arrives, it will override the oldest one.
I there any way in which I can achieve this with Firebase? If I receive more then one notification, to be grouped in a single one?
Thanks in advance!
If you want to use more customizable and advanced notification features.
You should only send FCM with data payload, and create notification at android client side.
Remember that if you send FCM with notification payload or notification + data payload, the notification will be created by android core system and BroadcastReceiver's onReceive method won't being called if your app is on background.
If you send FCM with data payload, it will call onReceive all the time, so you can produce custom notification manually at android client side. (most app uses latter method.)
I hope this link would be helpful.
I had this same confusion and realized I misunderstood what collapseKey and tag are for.
collapseKey will limit the number of notifications a client receives while they're offline, tag is what will stack notifications together in the drawer.
So for a typical cloud function, it should look like this:
const notification = {
notification: {
'title': 'Interesting title',
'body': 'Hello, world'
},
'data': {
'whatever': whatever,
},
'android':{
'collapseKey': collapseKey,
'priority': 'high',
'notification': {
'tag': tag,
}
},
'token': fcmToken
};
admin.messaging().send(notification)
Note that the "tag" parameter sits inside of the android notification, not the top-level notification.
The easiest and most flexible solution is to extend the FirebaseMessagingService and handle the notification yourself. But first instead of using notification on your notificationContent in your cloud function, you have to change that to data so that you send a data message instead of a notification message. The difference is that the notification message will have an implicit collapse key (the package name of the app), while the data message won't have one. But the data message needs to be handled on the client or else it won't be displayed.
Here's a sample of what you'll need for your FirebaseMessagingService:
public class MyFCMService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getNotification() != null) {
//this notification was sent from the Firebase console, because in our cloud function, we are using the DATA tag, not the notification tag
//so here we have to handle the notification that was sent from the console
...
} else if (remoteMessage.getData().get(KEY) != null) {
//this data message was sent from our cloud function
//KEY is one of the keys that you are using on the cloud function
//in your example, you are using the keys: title, body, icon, sound
//display the notification to the user
...
notificationManager.notify(TAG, ID, notificationBuilder.build());
//you have to use the same TAG and the same ID on each notification if you want your 2nd notification to simply update the text of the first one, instead of showing as a new notification
}
}
}
PS. When you send a notification from your cloud function (well if you use the data tag, it's actually a data message, not a notification message), then this method will be called, regardless if the app is in the background or in the foreground. HOWEVER, when you send a notification from the firebase console, this method will be called ONLY if the app is in the foreground. If the app is in the background, the Firebase SDK will handle the notification and show it to the user. In some cases, it makes sense to show a notification only when the user is not running the app, for example if you want to advertise some new features of the app. In that case, what you can do is use a unique tag on the notification console (e.g. "display_in_foreground") and check that tag on the client. If you have set that to true, you can show the notification even to users that are currently running the app, or if it's false you can choose not to show the notification. This check will happen only if the app is in the foreground. If it's in the background, this won't be called at all and the SDK will handle to show the notification.
Do we have any way to show heads up notification, when receive push from Firebase Cloud Messaging? In foreground it is possible using Notification. But there is no way to show heads up notification, when app in background, because onMessageReceived is not calling.
I tried to set priority to "high", but no result.
Do you have any ideas?
After browsing multiple solutions in stackoverflow.com, I found below explanation to be most helpful
How to handle notification when app in background in Firebase
In your Android OnMessageReceived function/method, only Data Payload (RemoteMessage.getData) will trigger your custom notification such as head-up notification when App is in background. Notification Payload (RemoteMessage.getNotification) will not trigger your heads-up notification, and instead default to showing just a tiny icon on your notification tray.
If you're using Firebase Cloud Functions, do check that the information you're sending through is in the data payload, and notification payload should be removed if you want the heads up notification to work. Having notification payload will default to showing just a tiny icon on the notification tray only.
Hope this piece of information helps, and happy coding.
I am using node.js as my server platform. The trick is to remove the 'notification' field and move the 'title' and 'body' fields to 'data'. For my case, I changed:
var message = {
token: targetID,
android:{
priority: 'high'
},
notification: {
title: 'X',
body: req.body.msg
},
data: {
topic: req.body.topic
}
};
to
var message = {
token: targetID,
android:{
priority: 'high'
},
data: {
topic: req.body.topic,
title: 'X',
body: req.body.msg
}
};
then...
fcm.send(message, function(err, response){...
Please follow the below steps..
Now just click next on following two steps with the default setup
This step is very important and this is the main part which will manage the device’s system tray to show as a heads-up notification.
Now click on review and then publish. Let me know if you get the expected result.
Regardless of what platform you are calling firebase, all what you need is to add Title and Body fields to Notification inside Android and of course Priority = High
var aMessage = new Message
{
Topic = "atopic",
Notification = new Notification { Body = body, Title = title },
Data = new Dictionary<string,string> { { "ReferenceId", refId.ToString() } },
Android = new AndroidConfig
{
Priority = Priority.High,
Notification = new AndroidNotification
{
Body = body,
Title = title,
Color = "#ffcc00",
Icon = "ic_notification",
Sound = "default",
ChannelId = "my_notification_channel"
},
},
};
Based on the documentation, it is my understanding that there are two types of messages that Firebase can send: Notification and Data. Also, they can be either collapsible or non-collapsible with non-collapsible being the default for data messages. This would mean that each message is delivered to the client app. See below:
However, when I send data messages to my client they are collapsed. For example, I send one and it appears in the notification bar with no problem but if I don't open it and another message comes in, it is replaced by the new message. Here's some of my code.
Data message:
//create the notification payload
let payload = {
data: {
title: 'Title',
context: context,
parent: parent,
body: user + " commented on your contribution.",
sound: 'default'
}
};
//send the notification
return admin.messaging().sendToDevice(userToken, payload).then(ok =>{
console.log('Notification sent to: ' + submitter);
}).catch(error => {
console.log('Could not send notification.');
});
What am I doing wrong? I want each notification to appear and not be replaced.
You are debugging at the wrong end. The actual problem is on the client side where you are posting the notification.
While posting the notification if the notification id is the same Android OS will replace the existing notification.
Look for the notify() in your code. Refer to this doc for more details : https://developer.android.com/reference/android/app/NotificationManager.html#notify(int, android.app.Notification)
I'm using com.google.firebase:firebase-messaging:10.0.1 for Android and trying to make the device vibrate while application is in background and a push notification is received.
I send following json to FCM server:
to: 'topics/...',
notification: {
title: 'New Message',
body: 'top security body',
sound: 'mysound',
action_click: 'top_security'
}
When the app is in foreground, the onMessageReceived method of FirebaseMessagingService is triggered and I can add vibration. But, when the app is in background, onMessageReceived is not called and I have no control on the vibration. My first thought was to use data block instead both for background and foreground, but iOS client does not receive pushes in background if there is no notification block.
So how can I add vibration to push notification when the app is in background?
P.S. When I turn on vibrate mode on the device, the push notification cause vibrating instead of playing the sound.
Use data payload instead of notification payload because data payload will trigger onMessageReceived even though the app is background or foreground. Your request will look like this
data: {
title: 'New Message',
body: 'top security body',
sound: 'mysound',
action_click: 'top_security'
}
To retrieve the data from data payload inside onMessageReceived, call remoteMessage.getData(); which will return the result in a Map<String,String>
For example:
Map<String, String> data = remoteMessage.getData();
String title = data.get("title");
String body = data.get("body");
Then customize the notification as you want with that data.
Hope this helps :)