I just want to know if it's really possible to save data when onMessageReceived is triggered. I want to show a notification badge inside my application to show how much notifications he received when the app was closed. The code I made is not working, I am receiving the notifications when my app is closed but I am unable to save an integer in sharedPreferences. Is it maybe because of the context? I'm not really sure, every answer is appreciated thanks!
class FirebaseMessagingServiceClass : FirebaseMessagingService(){
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
if (remoteMessage.notification != null){
val title = remoteMessage.notification?.title
val body = remoteMessage.notification?.body
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
val notificationBadgeCount = prefs.getInt("notification_badge_count", 0)
val prefsEditor = prefs?.edit()
prefsEditor?.putInt("notification_badge_count", notificationBadgeCount + 1)
prefsEditor?.apply()
NotificationHelper.displayNotification(applicationContext, "Status Channel", 1010, title!!, body!!)
}
}
}
Related
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:)
I'm implementing FCM in my application , so basically i have some data that i send using data-payload , onMessageReceived() is successfully triggered when app is on foreground , but when i rebooted my device for example , notification is not triggered , i tried all possible ways to solve this issue but no luck ,
Help is appreciated guys , thank you .
This is my data - payload
val notificationData = JSONObject()
val payload = JSONObject()
notificationData.put("to", "/topics/$userToken")
payload.put("title",title)
payload.put("body", body)
payload.put("notificationVibrate",isVibrationEnabled)
payload.put("notification_channel_id",getString(R.string.channelid))
notificationData.put("data", payload)
This is how i'm receiving data in my firebaseMessagingService
override fun onMessageReceived(remotemessage: RemoteMessage) {
super.onMessageReceived(remotemessage)
if(remotemessage.data.isNotEmpty()){
val data = remotemessage.data
val title = data["title"]
val body = data["body"]
val isVibrationEnabled = data["notificationVibrate"]?.toBoolean()
val notificationChannelId = data["notification_channel_id"]
FireNotification(title!!,body!!,isVibrationEnabled!!,notificationChannelId!!)
}
}
This is the function where i fire the notification
private fun FireNotification(title : String , body : String,isVibrationEnabled : Boolean,notificationchannelid : String){
val vibratePattern = longArrayOf(500L,500L,500L)
val notification = NotificationCompat.Builder(applicationContext, notificationchannelid)
notification.setContentTitle(body)
notification.setContentText(title)
notification.setSmallIcon(R.drawable.ic_baseline_notifications_active_24)
notification.setAutoCancel(true)
if(isVibrationEnabled){
notification.setVibrate(vibratePattern)
}
notificatomCompat.notify(1001, notification.build())
} ```
I was testing Push Notification from Firebase console
I succesfully recieved Notification when my App is in Background
But while in foreground whatever message I send the Notification message showing to me is like :
I dont know from where this Number is coming from.
Below is my code for creating notification :
override fun onMessageReceived(p0: RemoteMessage) {
super.onMessageReceived(p0)
p0.notification?.let {
val notif = NotificationCompat.Builder(this, "12345")
.setContentTitle(p0.from)
.setContentText(p0.to)
.setSmallIcon(R.drawable.ic_menu_send)
.build()
val manager = NotificationManagerCompat.from(applicationContext)
.notify(0, notif)
}
}
Below is the screenshot from Firebase Console :
Can someone tell me how I can receive my messages properly.
UPDATE:
Also why this difference in background & foreground notifications
Thanks in Advance.
You're sending Notification Message. You can get title and body as per below
override fun onMessageReceived(p0: RemoteMessage) {
super.onMessageReceived(p0)
val title = message.notification.title
val body= message.notification.body
p0.notification?.let {
val notif = NotificationCompat.Builder(this, "12345")
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(R.drawable.ic_menu_send)
.build()
val manager = NotificationManagerCompat.from(applicationContext)
.notify(0, notif)
}
You can get more info here
The data is coming from the variable p0
Specifically
.setContentTitle(p0.from)
.setContentText(p0.to)
To get the data/payload from a Remote Message you need to use the method getData()
So your overall notification creation looks something like
// Check if message contains a notification payload.
if (remoteMessage.getData().size() > 0) {
Log.d("Notification", "Message Notification called ");
if (remoteMessage.getData().get("action") != null) {
remoteNotification(remoteMessage.getData().get("action"), remoteMessage.getData().get("arg"));
return;
}
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 am working on an app in which I have to save all the notification coming from the server using firebase. I can save which notification is coming in the foreground and also I can save if notification is coming in the background but in a condition that if I clicked on the notification I can able to save it. But my main concern is if the user swipes the notification or clear the notification that means a user will not click on the notification, then how can I save it. Is there any method? Please help me to find a solution for this.
You probably have a class that extends FirebaseMessagingService so you can do stuff on the onMessageReceived function. You can use the RemoteMessage function getData() see docs to ge the message payload. From there you can access the title and other information. Of course you'll need to know about the structure of the notification received. So, to answer you question you can save the notification information when it is received in the background by simply saving it in the onMessageReceived method of your FirebaseMessagingService.
FCM stops receiving notifications when the app is killed see. So your best approach is to do as #D10S suggested and implement the saving and the sending in cloud functions. here's an example of how to send notifications. You'll need to make your app save the notification token to the real time database so the cloud function can read it and send the notification to the correct user.
To save your token to the Real Time database you'll need to add some code in your FirebaseInstanceIdService, specially in the onTokenRefresh method. You can have a location in your database called tokens and you can create an object with the user ID. So you could add the token to the server like so:
DatabaseReference ref = database.getReference("tokens");
Map<String, String> users = new HashMap<>();
users.put(userUID, token);
ref.setValueAsync(users);
Notifications which are coming from server will be received in onMessageReceived(RemoteMessage remoteMessage) , From remoteMessage object you will get title and body , which you can store in sqlite or in SharedPreference.
For Example:-
class FBMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.i("PVL", "MESSAGE RECEIVED!!");
if (remoteMessage.getNotification().getBody() != null) {
Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getNotification().getBody());
} else {
Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getData().get("message"));
}
}
}
onMessageReceived will get event in every state :-Killed ,background,foreground.
You can not save the notification if the user doesn't open it in the app, so if he swipes the notification there is no way to save it within the app.
An option is use Cloud Functions for Firebase:
https://firebase.google.com/docs/functions/
So you can create a function that send notification to your users, and then add code to add the behaviour that you are looking for: when you send a notification, save it.
#Suppress("DEPRECATION")
class MyFirebaseMessagingService : FirebaseMessagingService() {
val TAG = "FirebaseMessagingService"
#SuppressLint("LongLogTag")
override fun onMessageReceived(remoteMessage: RemoteMessage) {
Log.d(TAG, "sent phone: ${remoteMessage.from}")
if (remoteMessage.notification != null) {
showNotification(remoteMessage.notification?.title, remoteMessage.notification?.body)
}
}
private fun showNotification(title: String?, body: String?) {
val databaseHelper = DatabaseHelper(this)
// sharedPreferences=this.getSharedPreferences("SHARED_PREF" , Context.MODE_PRIVATE)
val intent = Intent(this, MenuscreenActivity::class.java)
databaseHelper.insertData(title, body, databaseHelper.FIRST_TABLE_NAME)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)
startActivity(intent)
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setSound(soundUri)
.setContentIntent(pendingIntent)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(0, notificationBuilder.build())
}
}
#Suppress("DEPRECATION")
class MyFirebaseMessagingService : FirebaseMessagingService() {
val TAG = "FirebaseMessagingService"
#SuppressLint("LongLogTag")
override fun onMessageReceived(remoteMessage: RemoteMessage) {
Log.d(TAG, "sent phone: ${remoteMessage.from}")
if (remoteMessage.notification != null) {
showNotification(remoteMessage.notification?.title, remoteMessage.notification?.body)
}
}
private fun showNotification(title: String?, body: String?) {
val databaseHelper = DatabaseHelper(this)
// sharedPreferences=this.getSharedPreferences("SHARED_PREF" , Context.MODE_PRIVATE)
val intent = Intent(this, MenuscreenActivity::class.java)
databaseHelper.insertData(title, body, databaseHelper.FIRST_TABLE_NAME)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)
startActivity(intent)
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setSound(soundUri)
.setContentIntent(pendingIntent)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(0, notificationBuilder.build())
}
}