android – Messages not always being received by Firebase Messaging Service-ThrowExceptions

Exception or error:

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?

How to solve:

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.

Leave a Reply

Your email address will not be published. Required fields are marked *