I'm creating notification using Firebase and FCM
class FcmServices: FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
sendNotification(remoteMessage)
}
override fun onNewToken(token: String) {
super.onNewToken(token)
}
private fun sendNotification(remoteMessage: RemoteMessage) {
val notifTitle = remoteMessage.notification?.title
val notifBody = remoteMessage.notification?.body
val builder: NotificationCompat.Builder?
val notificationManager =
this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channelId = "101"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_DEFAULT
val notificationChannel = NotificationChannel(channelId, "notification", importance)
notificationManager.createNotificationChannel(notificationChannel)
builder = NotificationCompat.Builder(applicationContext, notificationChannel.id)
} else {
builder = NotificationCompat.Builder(applicationContext)
}
val intent = Intent(this, NotifikasiActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setSmallIcon(R.drawable.logo_bprmsa)
.setLargeIcon(
BitmapFactory.decodeResource(
this.resources,
R.drawable.logo_bprmsa
)
)
.setContentIntent(pendingIntent)
.setContentTitle(notifTitle)
.setContentText(notifBody)
.setDefaults(Notification.DEFAULT_VIBRATE)
var alarmSound: Uri? = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
if (alarmSound == null) {
alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
if (alarmSound == null) {
alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
}
}
builder.setSound(alarmSound)
builder.setAutoCancel(true)
builder.setWhen(System.currentTimeMillis())
builder.setDefaults(NotificationCompat.DEFAULT_VIBRATE)
builder.priority = NotificationCompat.PRIORITY_HIGH
notificationManager.notify(Random().nextInt(), builder.build())
}
}
I need to open the NotificationActivity after click the notification received from Firebase, but the problem is the PendingIntent is not working while the app is in background state. Is there any different condition between foreground and background state code ?
And for the second, the layout of foreground and background is also different (background state without the icon shown)
https://firebase.google.com/docs/cloud-messaging/concept-options
Based on the official document from Google, it is intentional. The Icon and any other buttons or others you wish to display other than the title and the message won't display if your app is not running foreground.
Related
When I swipe up after the local notification comes, the application notifications don't appear on the screen for a while. What could be the reason for this? I've read something that when heads up notifications are swiped up, it sends a warning to the system to prevent heads up notifications for a certain period of time, but how can I prevent this? I don't have any problems getting notifications in my app other than that.
fun getChatChannels(): MutableList<NotificationChannel> {
val chatChannels = mutableListOf<NotificationChannel>()
val chatChannel = NotificationChannel(
IM_CHANNEL_ID,
Application.getString(R.string.chat_channel_name),
NotificationManager.IMPORTANCE_HIGH
)
chatChannel.setShowBadge(false)
chatChannel.group = MESSAGE_GROUP_ID
chatChannels.add(chatChannel)
return chatChannels }
private fun getChannelList(): MutableList<NotificationChannel> {
val channelList = mutableListOf<NotificationChannel>()
channelList.addAll(getChatChannels())
return channelList
}
fun createGroupsAndChannels() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager =
Application.instance.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannelGroups(getGroupList())
notificationManager.createNotificationChannels(getChannelList())
}
Log.d(TAG, "Channels and groups created")
}
fun showChatNotification(destinationAddress: String, messageId: String, message: String) {
ThreadManager.createUITask {
val name = if (domainContact != null) {
"${domainContact.firstName} ${domainContact.lastName}"
} else {
destinationAddress
}
val notificationIntent = Intent(Application.instance, MainActivity::class.java)
notificationIntent.putExtra(
Application.getString(R.string.key_conversation_participant),
destinationAddress
)
notificationIntent.flags = Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
val pendingIntent = PendingIntent.getActivity(
Application.instance,
destinationAddress.hashCode(),
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
val notificationId = UUID.randomUUID().hashCode()
val builder = NotificationCompat.Builder(Application.instance, IM_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification_message)
.setColor(ContextCompat.getColor(Application.instance, R.color.colorPrimary))
.setContentTitle(name)
.setContentText(message)
.setStyle(
NotificationCompat.BigTextStyle() // Expandable-Collapsible notification
.bigText(message)
)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setContentIntent(pendingIntent)
.setVisibility(VISIBILITY_PUBLIC)
.setAutoCancel(true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.addAction(getChatNotificationReplyAction(destinationAddress, notificationId, messageId))
}
chatNotifications.add(mapOf(destinationAddress to notificationId))
createNotifications(builder, notificationId)
Log.d(TAG, "Chat notification created")
}
private fun createNotifications(builder: NotificationCompat.Builder, notificationId: Int) {
with(NotificationManagerCompat.from(Application.instance)) {
notify(notificationId, builder.build())
}
}
I'm creating a chat app that sends and receives notifications through Firebase Cloud Functions. Let's suppose I have 2 friends, and each friend sends me 5 messages(5 notifications). When I open a chat in my chat list, I want all notifications for that chat to be dismissed and the others not.
Currently I can only dimiss 1 notification. If I get more than one notification the notificationManager.cancel(notificationId) doesn't work. I don't want to use notificationManager.cancelAll() as I just want to dismiss some notifications.
override fun onMessageReceived(remoteMessage: RemoteMessage) {
remoteMessage.notification.let { notification ->
val type = remoteMessage.data[NOTIFICATION_TYPE]
val notificationChannelId = getNotificationChannelId(type)
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val intent = Intent(this, HomeActivity::class.java)
val notificationIntent = setIntent(remoteMessage.data)
val stackBuilder: TaskStackBuilder = TaskStackBuilder.create(this)
stackBuilder.addParentStack(HomeActivity::class.java)
stackBuilder.addNextIntent(intent)
stackBuilder.addNextIntent(notificationIntent)
val pendingIntent: PendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationBuilder = NotificationCompat.Builder(this, notificationChannelId)
.setContentTitle(notification?.title ?: "")
.setContentText(notification?.body ?: "")
.setStyle(
NotificationCompat.BigTextStyle()
.bigText(notification?.body ?: "")
)
.setSmallIcon(R.drawable.ic_stat)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setSound(soundUri)
.setColor(ContextCompat.getColor(applicationContext, R.color.colorNotification))
.setVibrate(vibrationPattern)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
notify(remoteMessage.data, notificationManager, notificationBuilder)
}
}
private fun notify(
data: Map<String, String>,
notificationManager: NotificationManager,
notificationBuilder: NotificationCompat.Builder
) {
when (data[NOTIFICATION_TYPE]) {
CHAT_MSG -> {
if (data[NotificationUtils.CHAT_ID] != ChatActivity.currentChat) {
notificationManager.notify(
CHAT_MSG_NOTIFICATION_ID,
notificationBuilder.build()
)
}
}
FRIEND_REQUEST -> {
notificationManager.notify(
FRIEND_REQUEST_NOTIFICATION_ID,
notificationBuilder.build()
)
}
}
}
OnStart():
fun dismissNotifications(notificationId: Int) {
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(notificationId)
}
My thoughts is:
Save all notificationIds in map where:
key is userName/userId in message.
value is List of notificationId
When you need to clear all notifications you just ask you map and clear all that notificationIds for that userName/userId
I am trying to integrate Firebase Cloud Messages into my app. The code I used in the showNotification function is from the Android User Interface Samples. I tried it in the Activity and it worked but am not sure why it's not working in the service. The println is showing the function is getting called and values are coming as expected. Is there anything am missing from the function?
class MessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
if (remoteMessage.data.isNotEmpty()) {
val message = Gson().fromJson(remoteMessage.data.toString(), Message.Res::class.java).payload!!
showNotification(message.title, message.body, message.count)
}
}
private fun showNotification(title: String?, body: String?, count: Int = 0) {
println("_print::showNotification(title:$title, body:$body, count:$count)")
val mainPendingIntent = PendingIntent.getActivity(
applicationContext, BuildConfig.REQUEST_CODE,
Intent(applicationContext, MainActivity::class.java),
PendingIntent.FLAG_UPDATE_CURRENT
)
val builder = NotificationCompat.Builder(applicationContext, "channel_email_1")
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher_round))
.setContentIntent(mainPendingIntent)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setColor(ContextCompat.getColor(applicationContext, R.color.primary))
.setSubText(if (count > 1) "You have $count pending notifications" else title)
.setCategory(Notification.CATEGORY_EMAIL)
.setPriority(1)
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
NotificationManagerCompat.from(applicationContext)
.notify(BuildConfig.NOTIFICATION_ID, builder.build())
}
}
Instead of
val mainPendingIntent = PendingIntent.getActivity(
applicationContext, BuildConfig.REQUEST_CODE,
Intent(applicationContext, MainActivity::class.java),
PendingIntent.FLAG_UPDATE_CURRENT
)
NotificationManagerCompat.from(applicationContext)
.notify(BuildConfig.NOTIFICATION_ID, builder.build())
I use:
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Since android Oreo notification channel is needed.
setupChannels(notificationManager, builder)
// Create pending intent, mention the Activity which needs to be triggered
// when user clicks on notification.
val notificationId = Random.nextInt()
navigateToScreen(builder, notificationId)
val notification = builder.build()
notificationManager.notify(notificationId, notification)
}
private fun setupChannels(notificationManager: NotificationManager,
builder: NotificationCompat.Builder) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "channel_email_1"
val channel = NotificationChannel(channelId, "title",
NotificationManager.IMPORTANCE_DEFAULT).apply {
description = "body"
// Add other settings.
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
canShowBadge()
setShowBadge(true)
}
notificationManager.createNotificationChannel(channel)
builder.setChannelId(channelId)
}
}
private fun navigateToScreen(builder: NotificationCompat.Builder,
notificationId: Int) {
val intent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, notificationId, intent,
PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(pendingIntent)
}
An application receives push notifications. They can be different (payment, order, chat), so I have to show them all, not replacing old with new. A problem is that in old emulators (API 19) all push notifications are shown separately.
In newer emulators they are groupped into one, but (if I'm not mistaken) after 3 received notifications.
Data sent from FCM:
{
"to": "<push token>",
"data": {
"title": "Application name",
"message": "See a message",
"screen": "Main screen",
...
}
}
MyFirebaseMessagingService:
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val textStyle = NotificationCompat.BigTextStyle()
val title: String
val body: String
if (remoteMessage.data.isNullOrEmpty()) {
title = remoteMessage.notification?.title ?: ""
body = remoteMessage.notification?.body ?: ""
} else {
title = remoteMessage.data["title"] ?: ""
body = remoteMessage.data["message"] ?: ""
}
val notificationBuilder = NotificationCompat.Builder(this,
getString(R.string.default_notification_channel_id))
.setContentTitle(title)
.setContentText(body)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setStyle(textStyle)
.setSound(soundUri)
.setSmallIcon(R.drawable.ic_notification_icon)
.setAutoCancel(true) // Dismiss the notification on click.
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Since android Oreo notification channel is needed.
setupChannels(notificationManager, notificationBuilder)
// Create pending intent, mention the Activity which needs to be triggered
// when user clicks on notification.
val notificationId = Random.nextInt()
navigateToScreen(notificationBuilder, notificationId, remoteMessage)
val notification = notificationBuilder.build()
notificationManager.notify(notificationId, notification)
}
private fun setupChannels(notificationManager: NotificationManager,
notificationBuilder: NotificationCompat.Builder) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = getString(R.string.default_notification_channel_id)
val channel = NotificationChannel(channelId, "title",
NotificationManager.IMPORTANCE_DEFAULT).apply {
description = "body"
enableLights(true)
enableVibration(true)
lightColor = Color.CYAN
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
canShowBadge()
setShowBadge(true)
}
notificationManager.createNotificationChannel(channel)
notificationBuilder.setChannelId(channelId)
}
}
private fun navigateToScreen(notificationBuilder: NotificationCompat.Builder,
notificationId: Int,
remoteMessage: RemoteMessage) {
val intent = getNavigationIntent(remoteMessage)
val pendingIntent = PendingIntent.getActivity(this, notificationId, intent,
PendingIntent.FLAG_UPDATE_CURRENT)
notificationBuilder.setContentIntent(pendingIntent)
}
private fun getNavigationIntent(remoteMessage: RemoteMessage): Intent {
val intent = Intent(this, MainActivity::class.java)
intent.putExtra("screen", remoteMessage.data["screen"])
return intent
}
I have tried using "0" notification id and as well as unique notification id.
Also used setGroup() like below. It still generates a new notification every time. I want to merge the notification body and set the title as common.
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
super.onMessageReceived(remoteMessage)
remoteMessage?.let {
sendNotification(it.data["alert"])
}
}
private fun sendNotification(messageBody: String?) {
val channelId = "${this.packageName}-${this.getString(R.string.app_name)}"
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val builder = NotificationCompat.Builder(this, channelId).apply {
setDefaults(Notification.DEFAULT_ALL)
setSmallIcon(if (Build.VERSION.SDK_INT >= 21) R.mipmap.ic_launcher else R.mipmap.ic_launcher_round)
setContentTitle(getString(R.string.app_name))
setContentText(messageBody)
setDefaults(NotificationCompat.DEFAULT_SOUND or NotificationCompat.DEFAULT_VIBRATE or NotificationCompat.DEFAULT_LIGHTS)
setStyle(NotificationCompat.BigTextStyle().bigText(messageBody))
priority = NotificationCompat.PRIORITY_DEFAULT
setAutoCancel(true)
setSound(defaultSoundUri)
setGroup(getString(R.string.app_name))
setGroupSummary(true)
}
val manager = getSystemService(NOTIFICATION_SERVICE) as? NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelId, getString(R.string.default_channel_name), NotificationManager.IMPORTANCE_HIGH)
manager?.createNotificationChannel(channel)
}
val intent = Intent(this, DashboardFlowActivity::class.java)
intent.putExtra(DashboardFlowActivity.ISFROMNOTIFICATION, true)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)
builder.setContentIntent(pendingIntent)
//manager?.cancelAll()
manager?.notify(this.getString(R.string.app_name), getID(), builder.build())
}
}
private val c = AtomicInteger(0)
private fun getID(): Int {
return c.incrementAndGet()
}
Anything I am doing wrong here? Also, I have gone through this answer. setgroup() in notification not working
Finally I got solution for this question using https://stackoverflow.com/a/41114135/6021469, https://www.developer.com/ws/android/creating-bundled-notifications-with-android.html
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
super.onMessageReceived(remoteMessage)
remoteMessage?.let {
sendNotification(it.data["alert"])
}
}
private fun sendNotification(messageBody: String?) {
val channelId = "${this.packageName}-${this.getString(R.string.app_name)}"
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val builder = NotificationCompat.Builder(this, channelId).apply {
setDefaults(Notification.DEFAULT_ALL)
setSmallIcon(if (Build.VERSION.SDK_INT >= 21) R.mipmap.ic_launcher else R.mipmap.ic_launcher_round)
setContentTitle(getString(R.string.app_name))
setShowWhen(true)
setContentText(messageBody)
setDefaults(NotificationCompat.DEFAULT_SOUND or NotificationCompat.DEFAULT_VIBRATE or NotificationCompat.DEFAULT_LIGHTS)
setStyle(NotificationCompat.BigTextStyle().bigText(messageBody))
priority = NotificationCompat.PRIORITY_DEFAULT
setAutoCancel(true)
setShowWhen(true)
setSound(defaultSoundUri)
setGroup(getString(R.string.app_name))
}
val builderSummary = NotificationCompat.Builder(this, channelId).apply {
setDefaults(Notification.DEFAULT_ALL)
setSmallIcon(if (Build.VERSION.SDK_INT >= 21) R.mipmap.ic_launcher else R.mipmap.ic_launcher_round)
setContentTitle(getString(R.string.app_name))
setShowWhen(true)
setContentText(messageBody)
setDefaults(NotificationCompat.DEFAULT_SOUND or NotificationCompat.DEFAULT_VIBRATE or NotificationCompat.DEFAULT_LIGHTS)
setStyle(NotificationCompat.BigTextStyle().bigText(messageBody))
priority = NotificationCompat.PRIORITY_DEFAULT
setAutoCancel(true)
setShowWhen(true)
setSound(defaultSoundUri)
setGroup(getString(R.string.app_name))
setGroupSummary(true)
}
val manager = getSystemService(NOTIFICATION_SERVICE) as? NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelId, getString(R.string.default_channel_name), NotificationManager.IMPORTANCE_HIGH)
manager?.createNotificationChannel(channel)
}
val intent = Intent(this, DashboardFlowActivity::class.java)
intent.putExtra(DashboardFlowActivity.ISFROMNOTIFICATION, true)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)
builder.setContentIntent(pendingIntent)
manager?.notify(this.getString(R.string.app_name), getID(), builder.build())
manager?.notify(this.getString(R.string.app_name), 0, builderSummary.build())
}
}
private val c = AtomicInteger(0)
private fun getID(): Int {
return c.incrementAndGet()
}