I am using Firebase FCM service for my android app. Facing the listed down issues in it.
Sometimes when app receives notifications it doesn't sound. Below is the code snippet.
private fun createNotificationChannel(
context: Context, id: String, name: String, description: String,
path: Uri?, dnd: Boolean, importance: Int,
notificationManager: NotificationManager
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val existingChannel =
notificationManager.getNotificationChannel(id)
if (existingChannel != null) {
notificationManager.deleteNotificationChannel(id)
}
val mAudioManager =
context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
mAudioManager.setStreamVolume(
AudioManager.STREAM_ALARM,
mAudioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM),
0
)
val channel = NotificationChannel(id, name, importance)
channel.description = description
channel.enableLights(true)
channel.setShowBadge(true)
channel.describeContents()
channel.setBypassDnd(dnd)
channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
channel.lightColor = R.color.red
channel.enableVibration(true)
if (id == CHANNEL_ID_NORMAL_PRIORITY) {
if (!SharedPrefUtils.getSharedPrefIsAppInForeground(context)) {
channel.setSound(
path,
AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
)
}
} else if (id == CHANNEL_ID_HIGH_PRIORITY) {
channel.setSound(
path,
AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
)
}
notificationManager.createNotificationChannel(channel)
}
}
If App is not running for long time then the method onMessageReceived() of firebase messaging service is not getting called. In this case, when the app comes to the foreground, I am receiving notifications.
In push notification, I am sending only data payload because when the app is in background (either running or closed) and receives notification, if we use notification payload it won't set large icon to the banner. Below is code snippet for Push Notification.
AndroidConfig androidConfig = AndroidConfig.builder()
.setTtl(3600 * 1000)
.setPriority(AndroidConfig.Priority.HIGH)
//.setNotification(androidNotification)
.putData("title", title)
.putData("body", StringEscapeUtils.unescapeJava(content))
.putData("icon", icon)
.putData("sound", soundData)
.putData("channelid", channelId)
.build();
Message msg = Message.builder()
.setAndroidConfig(androidConfig)
.setToken(token)
.build();
String response = FirebaseMessaging.getInstance().send(msg);
Just like Micheal pointed out in the comment, this is (unfortunately) the expected behavior of the FCM when using the notification field.
Read more in the Handling messages section of the documentation. And the important bit:
The usual fix for such scenarios is to change the way FCMs are structured:
Do not use notification field (leave it completely unused), but use the data field and build your local push notifications based on that.
Related
I am trying to show a custom notification when I get a push notification from firebase, when the app is in background.
When the app is in background, the log messages START and END gets printed but does not show the notification on Android which I created as customNotification.
This is how I created a notification.
Could you please suggest what should be corrected please
override fun onMessageReceived(message: RemoteMessage) {
Log.d("FCMService", "onMessageReceived START")
//super.onMessageReceived(message)
// Get the layouts to use in the custom notification
val notificationLayout = RemoteViews(packageName, R.layout.plugin_requires_approval_notification_small)
val notificationLayoutExpanded = RemoteViews(packageName, R.layout.plugin_requires_approval_notification_large)
// Apply the layouts to the notification
val customNotification = NotificationCompat.Builder(this, "FcmService")
.setSmallIcon(R.mipmap.ic_launcher)
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(notificationLayout)
.setCustomBigContentView(notificationLayoutExpanded)
.build()
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(0, customNotification)
Log.d("FCMService", "onMessageReceived END")
}
Thanks in advance
R
EDIT
it is fixed now, the issue was with the CHANNEL_ID I provided.
for reference channelID should be the one used in the notificationChannel() function which looks like the bellow code, this is in the project App class.
private fun createNotificationChannels() {
// Do this only on API 26+ because the NotificationChannel
// class is new and not in the AndroidX library
if (SDK_INT >= O) {
val caInfoNotifChannel = NotificationChannel(CaInfoProcessingService.NOTIFICATION_CHANNEL_ID,
getString(R.string.ca_info_service_notif_channel_name),
IMPORTANCE_LOW).apply {
description = getString(R.string.ca_info_service_notif_channel_desc)
}
// Register the channel with the system
getSystemService<NotificationManager>()?.createNotificationChannel(caInfoNotifChannel)
}
}
In my app I am using FCM to get notifications. And everything is working when my app is running in foreground but problem starts when app goes in background or if app gets killed from background, in this case I am getting the notification but data is not uploading on the server.
For uploading data to the server I am using a separate class where all the required code is written and I am Just calling it in the FirebaseMessagingService() class.
I tried all possible ways, I tried to make separate service but it didn't work.
But I want to upload data to server When I am getting notification.
here is my FirebaseMessegingService Class
class FirebaseShareDevMessagingService : FirebaseMessagingService() {
private var resultIntent: Intent? = null
override fun onNewToken(p0: String) {
super.onNewToken(p0)
}
var mNotificationManager: NotificationManager? = null
#RequiresApi(Build.VERSION_CODES.O)
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
Log.d("remoteMessage", "onMessageReceived: ${remoteMessage.data}")
// playing audio and vibration when user se request
val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val r = RingtoneManager.getRingtone(this, notification)
r.play()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
r.isLooping = false
}
val data: MutableMap<String, String> = remoteMessage.data
val deviceId = data["username"]
val deviceName = data["address"]
val notificationType = data["notificationType"]
//codes
....
....
val pendingIntent =
PendingIntent.getActivity(this, 1, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentTitle(remoteMessage.notification!!.title)
builder.setContentText(remoteMessage.notification!!.body)
builder.setContentIntent(pendingIntent)
builder.setVibrate(longArrayOf(100, 300, 300, 300))
builder.setStyle(
NotificationCompat.BigTextStyle().bigText(
remoteMessage.notification!!.body
)
)
builder.setAutoCancel(true)
mNotificationManager =
applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "Your_channel_id"
val channel = NotificationChannel(
channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT
)
mNotificationManager!!.createNotificationChannel(channel)
builder.setChannelId(channelId)
}
mNotificationManager!!.notify(System.currentTimeMillis().toInt(), builder.build())
val cal = TimeStampConverter.getTimeStamp(remoteMessage.sentTime.toString())
Log.d("OnReceivedNotification", "onMessageReceived:$remoteMessage ")
// here i am calling helper class to upload data to
// server.....
BackendServerHelperClass(applicationContext).saveNotification(
System.currentTimeMillis().toInt(),
remoteMessage.notification!!.title!!,
remoteMessage.notification!!.body!!,
FirebaseAuth.getInstance().uid.toString(),
cal.time.toString(),
deviceId,
deviceName,
isAllowedSubLetting.toBoolean(),
notificationType!!.toInt() )
}
}
Please help, if there is any way to achieve this.
Updated
I tried to give permission of Screen overlay but still its not working
Help will be appreciated:)
Thanks
After a lot of research i found solution.
If we want to receive notification in background and want to do some other stuffs in background if notification is received so we should simply sent the "data" section instead "notification" section.
if we sent both "data" and "notification" then we will receive a notification in background but if you are doing some other stuffs in "onMessageReceive" like saving data to ROOM DATABASE or uploading some data to SERVER. , then you should sent only "data" section.
example of data section:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
}
This solved my problem.
You can read more about this on official FCM documentation.
Thanks!! Happy coding:)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val existingChannel = notificationManager.getNotificationChannel(id)
if (existingChannel != null) {
notificationManager.deleteNotificationChannel(id)
}
val channel = NotificationChannel(id, name, importance)
channel.description = description
channel.enableLights(true)
channel.setShowBadge(true)
channel.setBypassDnd(dnd)
channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
channel.lightColor = R.color.cornflower_blue_dark
channel.enableVibration(true)
channel.setSound(path,
AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
.build()
)
notificationManager?.createNotificationChannel(channel)
}
I want to play custom sound notifications in Android. I have mentioned that in notification channel. But setSound is not working.
When the app is in background it wont call onMessageReceived().
And the channel.setSound() is also not working.
I want to have App Provided Sound for notifications.
Let FCM handle notifications on device, if it's not a data message.
How can I force Android to show notification using FCM, even when app is in foreground? I don't want to build my own notification.
I am sending two types of messages to my app: data message and normal notification message. Data messages are handled in onMessageReceived(), no matter if the App is in background or foreground or killed which is OK. But now I am also sending normal notification messages through Firebase Console, and they are automatically displayed when app is in background but when app is in foreground, onMessageReceived() is called. Here, I would need to somehow tell FCM to show the contents without me having to build the notification.
I tried with:
#Override public void onMessageReceived(RemoteMessage remoteMessage) {
if(remoteMessage.getData() == null || !remoteMessage.getData().containsKey("specificKey")) {
// notification msg, let FCM handle it
super.onMessageReceived(remoteMessage); // this is not working - I want FCM to show notification the same as if the app was in background.
return;
} else {
// data message, I'm handling it on my own and showing a custom notification, working fine and well
}
}
But this is my own handling via code and I want FCM to do that somehow. How can I do that?
When the app is not in the foreground, notification messages are handled by the system. This is by definition and there is no way to change the behavior.
If you want to control what is displayed while the app is not in the foreground, you will have to send a data message.
In this, the else part needs to be handled by you to show a custom notification as follows:
class FCMMessagingService: FirebaseMessagingService() {
var dataMap: Map<String, String>? = null
var body: String = ""
var title: String = ""
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
super.onMessageReceived(remoteMessage)
dataMap = remoteMessage?.data
Log.d("Data Map", dataMap.toString())
try {
val jsonObject = JSONObject(dataMap?.get("data")!!)
val contentInfo = jsonObject.get("contentInfo") as JSONObject
val time = contentInfo.getString("time")
var message = jsonObject.getString("message")
message = message.replace("<time>", Utils.getTimeFromTimestamp(time.toLong(), true))
body = message
} catch (e:JSONException) {
e.printStackTrace()
}
title = dataMap?.get("title")!!
if(Foreground.get().foreground) {
sendBroadCast(title , body)
} else {
createNotification(title, body)
}
}
private fun createNotification(title: String, body: String) {
val intent = Intent(this, DashBoardActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(this, Calendar.getInstance().timeInMillis.toInt(), intent,
PendingIntent.FLAG_ONE_SHOT)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notification = NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.noti)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
notification.color = resources.getColor(R.color.toolBarColor)
}
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(Calendar.getInstance().timeInMillis.toInt(), notification.build())
}
private fun sendBroadCast(title: String, body: String) {
val broadCastIntent = Intent(Constant.NOTIFICATION)
broadCastIntent.putExtra("title", title)
broadCastIntent.putExtra("body", body)
LocalBroadcastManager.getInstance(this).sendBroadcast(broadCastIntent)
// val intent = Intent(this, DashBoardActivity::class.java)
// intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
}
I believe you will have to do it this way only as FCM won't handle it anyhow for you. I hope, this helps you.
I've read the ~10 similar questions to this on SO, and some other google search, and documentation pages, and I still can't figure out what the issue is.
Basically, if the app is closed (or backgrounded), the push notification icon shows up as a white square.
If the app is running, it shows up with the icon I want.
My icon is transparent, and just white. Its a simple icon that comes from Google itself.
Here's what I have, and where the issue may be.
Our app has multiple modules. I'll focus on 3 of them:
App
AppCode
PushNotification
I'm building the local notification on the PushNotification module:
override fun onMessageReceived(from: String?, data: Bundle?) {
super.onMessageReceived(from, data)
Log.d("PNReceiver", "onMessageReceived")
val notification = data?.get("notification") as Bundle?
val notificationTitle = notification?.get("title") as String
val notificationBody = notification?.get("body") as String
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channelId = getString(R.string.notification_channel_id)
if(manager.getNotificationChannel(channelId) == null) {
val channel = NotificationChannel(channelId,
getString(R.string.notification_channel_name),
NotificationManager.IMPORTANCE_DEFAULT)
channel.description =
getString(R.string.notification_channel_description)
manager.createNotificationChannel(channel)
}
createLocalNotification(manager, channelId, notificationTitle, notificationBody)
}
}
private fun createLocalNotification(notificationManager: NotificationManager,
channelId: String,
title: String,
body: String) {
val largeIcon = BitmapFactory.decodeResource(resources, R.drawable.ic_cake_variant)
val builder = NotificationCompat.Builder(this, channelId)
.setContentTitle(title)
.setContentText(body)
.setStyle(NotificationCompat.BigTextStyle().bigText(body))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setSmallIcon(R.drawable.ic_cake_variant)
.setLargeIcon(largeIcon)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND or Notification.DEFAULT_LIGHTS or Notification.DEFAULT_VIBRATE)
notificationManager.notify(0, builder.build())
}
Also, I'm trying to push the exact same icon, on the manifest of the PushNotification module:
<application>
... some gcm stuff...
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/notification_channel_id" />
<meta-data android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_cake_variant" />
</application>
The other 2 modules (App and AppCode) don't have anything related to the push notification code.
FWIW, our data flow/dependency graph of modules is App -> AppCode -> PushNotification
Also, we're still using GCM and not FCM, on version com.google.android.gms:play-services-gcm:11.8.0
Tried version 15.0.1, with no success either.
Am I missing something super obvious?
Thank you for your help.
UPDATE
Here's what the body of the received message looks like:
Bundle[{
google.sent_time = 1526919xxxxxx,
google.message_id = 0: 1526919xxxxxxx % xxx c5e8a46xxxxxx,
notification = Bundle[{
body = test message 1,
title = test title 1
}],
message = test message 1,
collapse_key = com.mycompany
}]
Also, here are some of the other answers I've reviewed:
Question 1
Question 2
Question 3