Friday 16 July 2021

FirebaseMessagingService immediately destroyed after being created

I am using a BroadcastReceiver to send a broadcast to restart the FirebaseMessagingService when the service is destroyed. However, when starting service this way, the FirebaseMessagingService gets immediately destroyed. When the service is destroyed, I will send another broadcast to the receiver and the loop continues indefinitely.

My code for FirebaseMessagingService.

@AndroidEntryPoint
class MessagingService :
    FirebaseMessagingService(),
    FirebaseAuth.AuthStateListener {
    companion object {
        var isRunning = false
        const val REQUEST_CODE = 0
        const val NOTIFICATION_ID = 0
    }

    @Inject
    lateinit var notificationRepository: NotificationRepository
    @Inject
    lateinit var authRepository: AuthRepository

    override fun onCreate() {
        super.onCreate()
        Log.d("MessagingService", "I am created")
        isRunning = true
        FirebaseAuth.getInstance().addAuthStateListener(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("MessagingService", "I am destroyed")
        isRunning = false
        FirebaseAuth.getInstance().removeAuthStateListener(this)
        val intent = Intent()
        intent.action = "restartMessagingService"
        intent.setClass(this, MessagingServiceRestarter::class.java)
        this.sendBroadcast(intent)
    }

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        val title = remoteMessage.notification?.title
        val message = remoteMessage.notification?.body
        if (message != null && title != null) {
            sendPushNotification(title, message)
        }
    }

    override fun onNewToken(token: String) {
        saveTokenToSharedPreferences(token)
        authRepository.getUser()?.let {
            val uid = it.uid
            sendTokenToFirestore(uid, token)
        }
    }

    override fun onAuthStateChanged(auth: FirebaseAuth) {
        auth.currentUser?.let {
            val uid = it.uid
            val savedRegistrationToken =
                PreferenceManager.getDefaultSharedPreferences(this)
                    .getString(getString(R.string.fcm_token_shared_pref_key), "")
            savedRegistrationToken?.let { token -> sendTokenToFirestore(uid, token) }
        }
    }

    private fun sendPushNotification(title: String, messageBody: String) {
        val intent = Intent(this, MainActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(this, REQUEST_CODE,
            intent, PendingIntent.FLAG_UPDATE_CURRENT)

        val channelId = getString(R.string.general_notification_channel_id)
        val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.mlearn_logo)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val channel = NotificationChannel(
            channelId,
            getString(R.string.general_notification_channel_name),
            NotificationManager.IMPORTANCE_DEFAULT
        )
        notificationManager.createNotificationChannel(channel)
        notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
    }

    private fun saveTokenToSharedPreferences(token: String) {
        val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
        with (sharedPref.edit()) {
            putString(getString(R.string.fcm_token_shared_pref_key), token)
            apply()
        }
    }

    private fun sendTokenToFirestore(uid: String, token: String) {
        GlobalScope.launch(Dispatchers.IO) {
            notificationRepository.sendNotificationToken(uid, token)
        }
    }
}

My code for the receiver.

class MessagingServiceRestarter : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d("MessagingService", "Restarter" + MessagingService.isRunning.toString())
        if (!MessagingService.isRunning) {
            context.startService(Intent(context, MessagingService::class.java))
            MessagingService.isRunning = true
        }
    }
}

I start my service every time the MainActivity is created.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("MessagingService", "MainActivity" + MessagingService.isRunning.toString())
        if (!MessagingService.isRunning) {
            val intent = Intent(this, MessagingService::class.java)
            startService(intent)
            MessagingService.isRunning = true
        }
    }

    override fun onDestroy() {
        val intent = Intent()
        Log.d("MessagingService", "MainActivity" + MessagingService.isRunning.toString())
        intent.action = "restartMessagingService"
        intent.setClass(this, MessagingServiceRestarter::class.java)
        sendBroadcast(intent)
        super.onDestroy()
    }

And I have registered my service and receiver on manifest.

        <service
            android:name=".service.MessagingService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        
        <receiver
            android:name=".receiver.MessagingServiceRestarter"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="restartMessagingService"></action>
            </intent-filter>
        </receiver>

How can I keep my FirebaseMessagingService running? I am using this receiver to restart the service when the service is stopped because the app is cleared from the recent apps.



from FirebaseMessagingService immediately destroyed after being created

No comments:

Post a Comment