TLDR: Messages send to Android devices via FCM take between 10 seconds and 5 minutes to get delivered. Probably due to priority. I set it to "high", but it seems like it doesn't stay on that value.
I develop an app both for iOS and Android. My backend runs on Django. For our realtime communication we recently started using Firebase Cloud Messaging (FCM).
I successfully managed to connect the Django server and am able to send messages to both kind of devices.
Here is my python code that constructs the message. Note that the token data gets appended later dynamically and that the messages are silent notifications.
def _build_silent_message(not_id, data):
"""Construct silent notifiation message.
Silent means that this message won't show up in the notifications hub
of the app.
"""
return {
'message': {
'data': {"data": data},
'apns': {
'payload': {
"notId": not_id, # notId HAS TO BE FIRST!!!
'aps': {
'content-available': 1
}
},
'headers': {
'apns-priority': '10'
},
},
'android': {
'priority': "high",
'data': {
"androidData": data,
'content-available': '1'
}
}
}
}
As you can see I set both the Apple and the Android priority to "high" (/ 10). On iOS all the messages get delivered immediately. On Android however this is not the case. Messages take up to 5 minutes until they arrive on the phones. I think this might be a priority issue, as the documentation states:
High priority. FCM attempts to deliver high priority messages immediately, allowing the FCM service to wake a sleeping device when necessary and to run some limited processing (including very limited network access).
So far so good. I set the priority to high. But the documentation further states:
High priority messages generally should result in user interaction with your app. If FCM detects a pattern in which they don't, your messages may be de-prioritized.
All my messages I sent to the devices do require interaction with the phone. But all my messages are silent messages. Maybe FCM thinks my messages aren't requiring user interaction and therefore gives it a lower priority.
Does any one know how to solve this?
EDIT: I tested with Android Samsung Galaxy S7 and Google Pixel 2.
You don't have access to the way FCM delivers the messages to the device. Just because you marked the message as high priority doesn't mean it is a high priority message that should be delivered immediately.
FCM will observe the interactivity of your notifications/FCM messages. If the user doesn't usually follow through with interacting with them FCM will de-prioritize your messages hence a longer delivery time.
FCM is intrusive in regards to UX...FCM was created in a way not to expose the user to irrelevant data. Think of it as an adBlocker that keeps you away from interrupting a user.
Check out the official documentation for FCM on how it works.
https://firebase.google.com/docs/cloud-messaging/concept-options
Related
Question
I have come across some voices stating that FCM data message delivery is less consistent compared to that of notification messages. Does anyone have direct experience or can point me to resources exploring the issue? Or is a notification message just a collapsible, high-priority data message that the Firebase SDK handles automatically?
https://stackoverflow.com/a/49998176
FCM data message not received in Android when the application is in background
About FCM's notification message and data message type, which has better receiving rate
The question does not consider the case of force quitting the app. In this scenario, both types of messages will not be delivered (to my knowledge).
Background
I am writing a new Android SDK for a push service provider (similar to OneSignal). The SDK should handle the display of push notifications by default, optionally the client app can handle incoming pushes itself.
The actual delivery is of course done by Firebase Cloud Messaging (on devices running Play Services). So there are 2 types of messages to choose from on FCM: data vs notification messages.
As data messages are consistently handled by the registered FirebaseMessagingService (provided there is no notification key in the payload), this should be the way to go for the SDK. [See documentation] So far, I have not been able to produce a situation in which a data message was not delivered (foreground or background).
By setting the priority in Message, We can reflect the delivery.
You have two options for assigning delivery priority to downstream messages on Android: normal and high priority. Delivery of normal and high priority messages works like this:
Normal priority. This is the default priority for data messages. Normal priority messages are delivered immediately when the device is not sleeping. When the device is in Doze mode, delivery may be delayed to conserve battery until the device exits doze. For less time-sensitive messages, such as notifications of new email, keeping your UI in sync, or syncing app data in the background, choose normal delivery priority.
When receiving a normal priority message on Android that requests a background data sync for your app, you can schedule a task with WorkManager to handle it when the network is available.
High priority. FCM attempts to deliver high priority messages immediately, allowing FCM to wake a sleeping device when necessary and to run some limited processing (including very limited network access). High priority messages generally should result in user interaction with your app or its notifications.
See Set and manage message priority topic in FireBase Documentation.
For More details you can prefer this link
For Displaying the Notification You Can Prefer this link
Best Of Luck In Advance.
I'm trying to push some high-priority data messages from a nodejs backend to the android client. Here is my code,
var payload = {
data
};
var options = {
priority: "high",
timeToLive: 0,
ttl: 0,
android: {
priority: "high",
timeToLive: 0,
ttl: 0,
},
};
admin.messaging()
.sendToDevice(deviceFcmId, payload, options)
.then(function (response) {})
.catch(function (response) {
console.error("error sendNotification", response);
});
As you can see, I'm using priority "high" and timeToLive: 0. But this does not wake up the device if it is in Doze mode, or sometimes even if the device is in an unlocked state, the message is delayed up to a few minutes. This is a voice-calling app, so the delivery delay should be minimal. I've searched similar posts on StackOverflow but nothing works for me. What am I missing here? Thanks in advance.
UPDATE:
In my app, there are two types of notifications, Chat notifications and Call notifications. When the user receives a chat notification, the app will write a Realm database entry and fetch the sender's profile picture from API, and shows the notification. I know it's a network call, but the thing is, the image fetching is managed by Glide so 90% of the time it will be a disk cache read rather than a network call (even the network call has a 1-second timeout, after this timeout, it will return a local image).
When the user receives a call notification, the app will start a service and ping the caller using socket.io. If the ping is a success it will show the call screen using a fullscreen intent by calling startForeground from the service. If the ping fails it will show a miscall notification and stops the service.
So, no matter whichever the case is there will always be a user-facing notification.
From the official docs
High priority messages on Android are meant for time sensitive, user visible content, and should result in user-facing notifications. If FCM detects a pattern in which messages do not result in user-facing notifications, your messages may be deprioritized to normal priority. FCM uses 7 days of message behavior when determining whether to deprioritize messages; it makes this determination independently for every instance of your application. If, in response to high priority messages, notifications are displayed in a way that is visible to the user, then your future high-priority messages will not be deprioritized.
This means your android app should pretty much just show a notification (make sure the app has notifications enabled). If you abuse this and instead try to directly do other things when receiving the push (such as open connections to the backend or do any other computationally-expensive task) then your messages might be downgraded to normal priority.
On a single device, you can verify if a message has been deprioritized by checking if getPriority() returns a lower value than getOriginalPriority().
And for all messages, you can query the Data API.
We are choosing to use FCM's notification message or data message (only for custom designs). We already know that custom designs data message perform better than the non custom design data messages. But we are wondering if notification message can have better receive rate than data message because it is using the system to show the notification. Anyone has done any investigation?
If not, then what's the advantages the notification message type have
It's an interesting question and topic of research. I faced the same
the situation about a while ago.
According to firebase's documentation :
Notification messages are high priority by default, and
collapsible--the following message will replace the current message if
it's not delivered yet.
In the custom data type payload, you can actually pass the notification priority to high. But.....
According to this document from firebase
High priority. FCM attempts to deliver high priority messages
immediately, allowing the FCM service to wake a sleeping device when
necessary and to run some limited processing (including very limited
network access). High priority messages generally should result in
user interaction with your app or its notifications. If FCM detects a
pattern in which they don't, your messages may be de-prioritized.
Android P introduced app standby buckets which limit the number of FCM
high priority messages you can send to your app that don't result in
the user using your app or viewing a notification. If in response to
a high priority message, a notification is displayed in a way that is
visible to the user, then your app standby bucket quota will not be
consumed by that message.
And now let's talk about my personal experience. I faced the same
situation and the observations we noted with our QA were quite the
same as their documentation.
Although after setting priority HIGH in data type payload we noticed random behaviour with some custom OS phones like Oneplus, Oppo etc. While in the case of notification type payload it was consistent and we were getting notification perfectly.
So I advise that if you don't have a particular requirement to handle
the data silently in the background just go with a simple
notification payload.
I am sending "Data" messages with Firebase to my app, but when the app is in Doze mode, those messages are not handled by FirebaseMessagingService, even when my app is whitelisted for battery optimisation and my messages marked as priority.
Firebase docs on why I choose "Data" messages instead of notification.
Android mechanism to add app to whitelist and skip battery optimisation.
Firebase priority messages according to documentation.
I follow all this steps, and even after this, messages are not handed to my implementation of FirebaseMessagingService.
Any idea how to force messages be handed by FirebaseMessagingService, even in Doze mode?
Note: I'm working on a VoIp app, if message its not immediately handed, its no longer valid and the purpose of it is lost.
If you are following all the documentation, it may still be the case that FCM has deprioritized your messages, as described in the documentation:
High priority messages generally should result in user interaction
with your app or its notifications. If FCM detects a pattern in which
they don't, your messages may be de-prioritized. Android P introduced
app standby buckets which limit the number of FCM high priority
messages you can send to your app that don't result in the user using
your app or viewing a notification. If, in response to a high priority
message, a notification is displayed in a way that is visible to the
user, then your app standby bucket quota will not be consumed by that
message.
There is no "force" mode that lets you operate above the rules stated in the documentation. If anyone could simply bypass the rules, then everyone would do it, and the rules would become useless to the end user, who is just trying to save their battery from apps that aren't following best practices.
After a while we found out the problem.
In server side instead of implementing the newest API the legacy one was implemented.
They have a different payload that can be seen here: Firebase Payload
basically instead of :
"android":{
"ttl": "0s",
"priority": "high"
}
we had to use:
"priority": 10,
"time_to_live": 0
I use Firebase high priority push notifications to trigger Panic alarms in Android devices. For first few tries of push, immediately push notifications arrives and it works great. But when i keep triggering push notifications after certain amount of time slowly delay keeps increasing.
I want it to trigger immediately as it is Panic situation.
I also followed the documentation which read:
High priority: FCM attempts to deliver high priority messages immediately, allowing the FCM service to wake a sleeping device when necessary and to run some limited processing (including very limited network access). High priority messages generally should result in user interaction with your app or its notifications. If FCM detects a pattern in which they don't, your messages may be de-prioritized. Android P introduced app standby buckets which limit the number of FCM high priority messages you can send to your app that don't result in the user using your app or viewing a notification. If, in response to a high priority message, a notification is displayed in a way that is visible to the user, then your app standby bucket quota will not be consumed by that message.
Because a small portion of the Android mobile population are on high latency networks, avoid opening a connection to your servers before displaying a notification. Calling back to the server before the end of the allowed processing time may be risky for users on high latency networks. Instead, include the notification content in the FCM message and display it immediately. If you need to sync for additional in-app content on Android, you can schedule an FJD job or a JobIntentService to handle that in the background.
How can I make sure high priority messages are triggered as soon as possible? May be within a minute in all cases.
FCM attempts to deliver high priority messages immediately, allowing the FCM service to wake a sleeping device when necessary and to run some limited processing (including very limited network access). High priority messages generally should result in user interaction with your app or its notifications. If FCM detects a pattern (such as testing pattern) then your messages may be de-prioritized. Android P introduced app standby buckets which limit the number of FCM high priority messages you can send to your app that don't result in the user using your app or viewing a notification. If, in response to a high priority message, a notification is displayed in a way that is visible to the user, then your app standby bucket quota will not be consumed by that message.