Android FCM Push Channel Id is always null - android

I have a custom notification channel that never gets triggered. I read all the documentation for server and client but I'm still missing something.
What I want
I want to send a high-priority push notification via FCM to eventually wake up a foreground service in the app. Therefore I defined a custom notification channel. I want to receive the push, find out that it was sent to the custom channel, and show a notification.
My Problem
I receive all push notifications from firebase as expected but the channelId is always null.
The Setup
We use FCM directly on both sides, the server and the android app.
Our users use Android 8.1 and higher. No legacy push is needed.
The backend sends a JSON that looks like the following:
{
"notification": {
"android_channel_id": "MY_High_Prio_Push_Channel"
},
"data": {
"notificationBody": "BodyText",
"notificationTitle": "Title"
},
"priority": "high"
}
The App has registered the push channel successfully. I can see it in the device settings. The push channel will be re-registered on any app start like this
private fun registerHighPrioPushToRestartTheForegroundService() {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(getString(R.string.push_channel_id_high_prio), getString(R.string.push_channgel_sync_with_high_prio), NotificationManager.IMPORTANCE_HIGH)
channel.setShowBadge(true)
notificationManager.createNotificationChannel(channel)
}
At Runtime
If the android device receives a push from FCM onNewMessageReceived() is called. I then check what channelId it was sent to by calling:
if (remoteMessage.notification?.channelId == getString(R.string.push_channel_id_high_prio)) {
// I would love to do my channel specific stuff here
}
As you can see in the screenshot below the body contains the full JSON. All other values are null.

The problem was on the server side. The whole JSON for the push was put in the body tag of the notification. Now that this is fixed we send a JSON like the following and the parsing in the client works as expected. We removed the notification tag so that onMessageReceived() will be called on every single push.
{
"to": "{devicePushToken}",
"android": {
"priority": "high"
},
"priority": 10,
"data": {
"title": "Some Title",
"body": "Some Message",
"android_channel_id": "yourUniquePushId"
}
}

Related

Ionic / Capacitor - PushNotiifcations - Android - “notification” + “data” message

I am using PushNotifications Capacitor plugin and FCM to send the notifications, everything works fine until I want to send a Push Notification with both notification and data fields on Android.
What I want to do is to send a custom data with the notification and consume the notification on app resume. I am using PushNotifications.getDeliveredNotifications() method to get the notifications on resume, on iOS I get all the notifications with proper data, but on Android data property is replaced with the object below:
{
body: "My Body",
data: {
android.appInfo: "ApplicationInfo{809371c app}",
android.bigText: "My Body",
android.progress: 0,
android.progressIndeterminate: false,
android.progressMax: 0,
android.reduced.images: true,
android.showChronometer: false,
android.showWhen: true,
android.template: "android.app.Notification$BigTextStyle",
android.text: "My Body",
android.title: "My Title",
gameDndOn: false,
specialType: "",
topFullscreen: false,
groupSummary: false,
id: 0,
title: "My Title"
}
}
I see in the FCM docs for Android apps that if both notification and data fields are present and the app is in the background the notification lands in the system tray and data in extras of the intent.
I am getting proper data when I tap on the notification, but in my case I want to get that on resume, without tapping on the notification.
Is there any way to get to that data in that case?
You have to create the message in this format
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
},
"data" : {
"Nick" : "Mario",
"Room" : "PortugalVSDenmark"
}
}
}
Note : notification structure is critical for receiving a notification. You need to have title and body. This gets displayed in the notification drawer.
data can be customized as per your requirement. This will have the data that you need inside your app.
Suggestion, keep your payload small. Send data which is absolutely necessary and also safe to send over FCM.
Look at this part of the official documentation
For handling push notifications in capacitor, you should use the listeners. Here is the official docs way of doing it.

Firebase notification won't default to `title_loc_key` if normal `title` is set

I'm using com.google.firebase:firebase-messaging:20.0.0 on Android. When I try sending a notification like the one below it always shows the normal title and body instead of title_loc_key and body_loc_key when they are presented in the app! The fun thing is that it's not the case in iOS. In iOS it will always try to first show the localized resources and if it couldn't find them, it will default to normal ones.
{
"to" : "f6_numko7IQ:APA91bFrTN0fmThFDeAFy2...",
"collapse_key" : "type_a",
"notification" : {
"title_loc_key": "resource_name_1",
"body_loc_key": "resource_name_2",
"title": "Default Title",
"body": "Default Body!"
}
}
Is this a known issue? Is there a get around for it?
The solution is to remove the "title" and "body" entries. I know it should work like on iOS but currently it's not.
{
"to" : "f6_numko7IQ:APA91bFrTN0fmThFDeAFy2...",
"collapse_key" : "type_a",
"notification" : {
"title_loc_key": "resource_name_1",
"body_loc_key": "resource_name_2",
}
}
For Android: Using the "v1" api from firebase remove "title" and "body" from root "notification: {....}" and add into the "android": {
"notification": {
"title_loc_key": "push_notification_title",
"body_loc_key": "push_notification_body"
}
},", should work.
But you need to keep in mind the following:
The push notification will be displayed by default by firebase SDK based on the com.google.firebase.MESSAGING_EVENT, when the app is in the background --> opened (the process is in the background) and Notification permission is allowed. Also, you need to be sure that your app has already a channel created with the default_channel_id you defined in the manifest file. For this case, you will not be notified of the onMessageReceived callback provided by "FirebaseMessagingService".
When the app is in the foreground you will not receive any firebase notification, visible on the screen. Based on the Channel you have created at point 1) you need to trigger the notification display if required, by creating a NotificationBuilder .... and displaying it. This catch must happen inside the: onMessageReceived callback provided by "FirebaseMessagingService"
When the app is closed and notification is allowed the push notification will be displayed by default by firebase SDK based on the com.google.firebase.MESSAGING_EVENT. However, if the notification received by the device contains some data: {} payload that can be handled into the onCreate lifecycle method from activity by accessing the this.intent.extras. You will not be notified of the onMessageReceived callback provided by "FirebaseMessagingService".
If notification is disabled you will not get any push notification displayed visually but when the app is in the foreground you will be notified into the onMessageReceived callback provided by "FirebaseMessagingService". When the app is closed or in the background, you will get nothing.

react-native-fcm application does not show notification of data type when it is killed

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.

FCM Push notifications does not show heads display on notification on top of screen

We are using firebase push notification in Android and in iOS. The push is sent using FCM REST API call. Push type is notification with extra data node.
Here is a sample payload:
{
"notification" : {
"title": "title text",
"body": "message body text",
"sound": "default"
},
"data": {
"messageType": "xxx"
},
"to": "yyy",
"priority": "high",
"time_to_live": 0
}
This type of push notification does not show a heads up display when the app is in background and phone is on. -- Notification just are added to notifications bar but are not sneak peaked to user at the top of the screen. -- no matter if the current app is full screen app or not.
One solution that I have tried and is working is to shift to pure data message where we will not send any notification node, but just the data node and write the code to show notification ourselves and set notification priority to Max (ie .setPriority(Notification.PRIORITY_MAX)) on notification builder object.
But this seems to have issues on iOS where data only pushes are not received/shown to user if the app killed by user.
So is there any workaround to this? any solution that works on Android, but also does not break iOS.
You should set the NotificationPriority to PRIORITY_HIGH or PRIORITY_MAX for Android to show the notification. See Android Notification and Notification Priority for more details.
You should set these values using the constants, not using the strings. E.g.
{
token,
android: {
notification:
{
title,
body,
// See https://developer.android.com/reference/android/app/Notification#PRIORITY_MAX.
// This is deprecated in Android API level 26, but works for older versions.
notification_priority: 2,
// Always allow Android users to see the message in its entirety.
// See https://developer.android.com/reference/android/app/Notification#VISIBILITY_PUBLIC
visibility: 1
}
}
}

Urban Airship - Aggregating Similar Push Notifications on Messaging Platform

I am creating a messaging application, and like any mobile messaging service Push Notifications are needed for when the app isn't connected to the backend.
Let me use an example to out line the scenario I'm experiencing.
There is a conversation between User A & User B
// User B's application is idle (not receiving messages from our backend)
// User A sends User B a message
A --> B
Because User B isn't connected, he/she is sent a push notification beckoning him/her to open the app and sync the message.
User B's phone now has one notification on his/her lock screen, like so
Message from User A
then ...
// User A sends User B another message
A --> B
User B's phone now has two separate notifications on his/her lock screen from User A.
These messages read like this:
Message from User A
Message from User A
BUT, I would like the lockscreen to read something like this
Message from User A (2)
I am unsure how to get the notifications to aggregate once they reach the phone, assuming they have metadata attached to them that articulates who the "sender" of the message is.
Currently, this is the payload I am sending up to Urban Airship
function sendPushNotification (event, user) {
if (event.type == 21 || event.type == 22 || event.type == 24) {
var sender = event.sender.username;
var alert = "from #" + sender;
var reciever = user.username;
var payload = {
"audience": {
"alias" : reciever
},
"device_types": [ "ios", "android" ],
"notification": {
"ios": {
"alert": alert,
"badge": "+1",
"sound": "default",
"extra": { "username": sender }
},
"android": {
"alert": alert,
"collapse_key": "inboxappco",
"extra": { "username": sender }
}
}
};
console.log("Hello 2");
pushNotification(payload);
} else {
// modularize for general purpose notifications
}
}; // end sendPushNotification function
Any advice on how I can leverage the the sender metadata, to aggregate consecutive push notifications from the same person into one line item on the lock screen?
Thanks in advance SOF.
It appears that your app will need to create your own custom push notification object and somehow get access to the NotificationManager
PushManager.shared().setNotificationBuilder(new YourCustomNotificationObject());
I'm not sure how Urban Airship exposes the NotificationManager, but you need to use the setGroup("arbitrarygroupname") accessor in your NotificationBuilder
Unless you are targeting minimum API level 20, then this is accessor is not available, so you have to use the v4+ NotificationCompat.Builder object, and make sure your support libraries are version 20 or higher.
EDIT, as of UrbanAirship 4.0.3 for Android this is not possible, server side you can keep track of a series of push notifications and use the collapse_key parameters with each push, collapse_key will replace push notifications of the same type, so your SERVER will have to send push notifications with different names, with the name being Message from User A (2) instead of letting the Android system handle that client side

Categories

Resources