Fcm Notification not triggered in background or when device is rebooted - android

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())
} ```

Related

Upload data to server from background through FirebaseMessegingService class

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:)

Save data in Shared Preferences when Message Received in FCM

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!!)
}
}
}

Foreground Notification showing numbers instead of message in android

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;
}

Messages not always being received by Firebase Messaging Service

In my chat app I use FCM with Firebase Functions to send notifications whenever a user receives a new message.
For that I have a FirebaseMessagingService that overrides the onMessageReceived. Aside from that, this Service also overrides onNewToken. Whenever the user first starts the app, the onNewToken gets called and I retrieve a new token and store it in the Firebase Realtime Database.
I then go chat with some user (without closing the app). When I receive new messages, I get the notification. The onMessageReceived gets called.
The problem is, when I close the app and later open it (or turn off emulator and start it up again), and I get a new message from that same previous chat, the service does not get called. I know for a fact that the problem isn't with the Firebase Functions because in my console log I get a Success Message.
Does the Firebase Messaging Service stop when I close and re-open the app?
Here is the code for my Firebase Messaging Service
class MyFirebaseInstanceId : FirebaseMessagingService() {
private lateinit var sp: SharedPreferences
private lateinit var auth: FirebaseAuth
private lateinit var uid: String
private lateinit var token: String
override fun onMessageReceived(p0: RemoteMessage) {
super.onMessageReceived(p0)
if (p0.data.isNotEmpty()) {
val payload: Map<String, String> = p0.data
sendNotification(payload)
}
}
override fun onNewToken(p0: String) {
super.onNewToken(p0)
// Save the new token
sp = getSharedPreferences("AUTH_UID", Context.MODE_PRIVATE)
token = p0
auth = FirebaseAuth.getInstance()
signIn()
}
private fun signIn() {
auth.signInAnonymously().addOnCompleteListener { task ->
if (task.isSuccessful) {
uid = auth.currentUser?.uid.toString()
sp.edit().putString("CURRENT_UID", uid).apply()
sp.edit().putString("CURRENT_TOKEN", token).apply()
FirebaseDatabase.getInstance().reference.child("users").child(uid).child("token")
.setValue(token)
startActivity(
Intent(
this,
MainActivity::class.java
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
}
}
}
private fun sendNotification(payload: Map<String, String>) {
createNotificationChannel()
createNotification(payload)
}
private fun createNotification(payload: Map<String, String>) {
val builder = NotificationCompat.Builder(this)
builder.setSmallIcon(R.drawable.ic_message_not)
builder.setContentTitle(payload["title"])
builder.setContentText(payload["text"])
builder.priority = NotificationCompat.PRIORITY_DEFAULT
builder.setChannelId(Constants.CHANNEL_ID)
val intent = Intent(this, MainActivity::class.java)
val stackBuilder = TaskStackBuilder.create(this)
stackBuilder.addNextIntent(intent)
val resultPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(resultPendingIntent)
val notificationManager =
(getSystemService(Context.NOTIFICATION_SERVICE)) as NotificationManager
notificationManager.notify(0, builder.build())
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create the NotificationChannel
val name = getString(R.string.channel_name)
val descriptionText = getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_DEFAULT
val mChannel = NotificationChannel(Constants.CHANNEL_ID, name, importance)
mChannel.description = descriptionText
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)
}
}
}
Basically, in my Splash Activity I check if it is the first time the user opens the app.
If it is, the login is made from the Service if it is not, the login is made from the Splash Activity.
This is the code for my Splash Activity:
class SplashActivity : AppCompatActivity() {
private lateinit var sp: SharedPreferences
private lateinit var auth: FirebaseAuth
private var flag: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
// If it is first time user enters the app, wait for the MyFirebaseServiceId
// If not, authenticate and sign in (since we already have the token)
sp = getSharedPreferences("FIRST_LOGIN", Context.MODE_PRIVATE)
flag = sp.getBoolean("IS_FIRST_TIME", true)
if (!flag) {
auth = FirebaseAuth.getInstance()
signIn()
}
sp.edit().putBoolean("IS_FIRST_TIME", false).apply()
}
private fun signIn() {
auth.signInAnonymously().addOnCompleteListener { task ->
if (task.isSuccessful) {
sp = getSharedPreferences("AUTH_UID", Context.MODE_PRIVATE)
sp.edit().putString("CURRENT_UID", auth.currentUser?.uid).apply()
getFCMToken()
Handler().postDelayed({
startActivity(Intent(this, MainActivity::class.java))
finish()
}, 2000)
}
}
}
private fun getFCMToken() {
FirebaseInstanceId.getInstance().instanceId.addOnCompleteListener { p0 ->
if (p0.isSuccessful) {
val token = p0.result?.token.toString()
//sp = getSharedPreferences("AUTH_UID", Context.MODE_PRIVATE)
sp.edit().putString("CURRENT_TOKEN", token).apply()
}
}
}
}
What is the problem and why am I not receiving messages all the time?
I faced the same Issue. And It is not the fault of android side.
You can solve this problem by editing notification model/structure by not using any keyword as key,arry name or object name that says notification. Lets say notification {} ===> data{}
NOTE: after doing this you will not receive sounded notice or Automatic notification. You need to manually get the data from the this message and create custom notification using notification manager. Add tittle to it priority and other things...
Doing this you will resolve the problem of notification not being received in background. If you need further assist I can help.

How to let FCM display notification even when app is in foreground?

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.

Categories

Resources