package com.example.myapp.services
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import com.example.myapp.R
import com.example.myapp.ui.MainActivity
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class MyFirebaseMessagingService : FirebaseMessagingService() {
@Inject
lateinit var tokenManager: TokenManager
override fun onNewToken(token: String) {
super.onNewToken(token)
// Send token to backend server
tokenManager.saveFcmToken(token)
// TODO: Send to server via API
}
override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)
// Handle data payload
message.data.isNotEmpty().let {
handleDataMessage(message.data)
}
// Handle notification payload
message.notification?.let {
sendNotification(
title = it.title ?: "New Message",
body = it.body ?: "",
data = message.data
)
}
}
private fun handleDataMessage(data: Map<String, String>) {
val type = data["type"]
when (type) {
"new_post" -> {
val postId = data["post_id"]?.toIntOrNull()
postId?.let {
sendNotification(
title = "New Post",
body = data["title"] ?: "",
data = mapOf("post_id" to it.toString())
)
}
}
"new_comment" -> {
// Handle comment notification
}
"new_like" -> {
// Handle like notification
}
}
}
private fun sendNotification(
title: String,
body: String,
data: Map<String, String> = emptyMap()
) {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
data["post_id"]?.let {
putExtra("post_id", it.toInt())
}
}
val pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val channelId = "default_channel"
createNotificationChannel(channelId)
val notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build()
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
notificationManager.notify(System.currentTimeMillis().toInt(), notification)
}
private fun createNotificationChannel(channelId: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId,
"Default Notifications",
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "Notifications for new posts and comments"
}
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
}
package com.example.myapp.data
import com.google.firebase.messaging.FirebaseMessaging
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class FcmManager @Inject constructor(
private val apiService: ApiService,
private val preferencesManager: SecurePreferencesManager
) {
suspend fun registerDevice(): Result<String> = try {
val token = FirebaseMessaging.getInstance().token.await()
preferencesManager.fcmToken = token
// Register with backend
apiService.registerFcmToken(token)
Result.success(token)
} catch (e: Exception) {
Result.failure(e)
}
suspend fun subscribeToTopic(topic: String): Result<Unit> = try {
FirebaseMessaging.getInstance().subscribeToTopic(topic).await()
Result.success(Unit)
} catch (e: Exception) {
Result.failure(e)
}
suspend fun unsubscribeFromTopic(topic: String): Result<Unit> = try {
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic).await()
Result.success(Unit)
} catch (e: Exception) {
Result.failure(e)
}
suspend fun subscribeToUserTopics(userId: Int) {
subscribeToTopic("user_$userId")
subscribeToTopic("all_users")
}
suspend fun unregisterDevice() {
preferencesManager.fcmToken?.let { token ->
try {
apiService.unregisterFcmToken(token)
preferencesManager.fcmToken = null
} catch (e: Exception) {
// Log error
}
}
}
}
Firebase Cloud Messaging (FCM) delivers push notifications across platforms. I extend FirebaseMessagingService and override onMessageReceived() to handle incoming messages. Device tokens obtained via FirebaseMessaging.getInstance().token register with backend. Notification channels define priority and behavior on Android 8+. Data messages execute app logic, while notification messages show system notifications. RemoteMessage contains data and notification payloads. Topics enable broadcast messaging with subscribeToTopic(). Background and foreground messages require different handling. Analytics track delivery and engagement. FCM ensures reliable, real-time communication for user engagement and updates.