Push with Cloud Messaging
Send and receive FCM notifications.
Push with Cloud Messaging is a free Android Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is Cloud Messaging?
Firebase Cloud Messaging (FCM) delivers push notifications and data messages to your app — even when it's closed.
The flow is simple:
- Each app install gets a unique registration token.
- Your server (or the Firebase console) sends a message to that token (or to a topic).
- FCM routes it to the device, which shows or handles it.
Add the Messaging Dependency
FCM ships in the firebase-messaging library, versioned by the BoM you set up earlier.
No version number is needed when the BoM is present.
// app/build.gradle.kts
dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.1.0"))
implementation("com.google.firebase:firebase-messaging")
}The Notifications Permission
On Android 13 (API 33) and above, posting notifications requires the runtime permission POST_NOTIFICATIONS.
Declare it in the manifest, then request it at runtime — without the grant your notifications are silently dropped.
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />Requesting the Permission
Use the Activity Result API to ask for POST_NOTIFICATIONS at runtime. Only request it on API 33+; older versions grant it implicitly.
import android.Manifest
import android.os.Build
import androidx.activity.result.contract.ActivityResultContracts
val requestPermission = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
println(if (granted) "Notifications allowed" else "Notifications denied")
}
fun askNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermission.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}The Registration Token
Each install has a unique FCM token that identifies it as a target. Fetch it with Firebase.messaging.token.
Send this token to your backend so it can push to that specific device. Tokens can change, so always treat the latest one as authoritative.
import com.google.firebase.Firebase
import com.google.firebase.messaging.messaging
import kotlinx.coroutines.tasks.await
suspend fun currentToken(): String {
return Firebase.messaging.token.await()
}The Messaging Service
To receive messages you extend FirebaseMessagingService. Override onMessageReceived to handle incoming payloads and onNewToken to react when the token rotates.
Register the service in the manifest with the FCM intent filter.
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
class MyFcmService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
// Upload the fresh token to your backend
sendTokenToServer(token)
}
override fun onMessageReceived(message: RemoteMessage) {
val title = message.notification?.title ?: "New message"
val body = message.notification?.body ?: ""
showNotification(title, body)
}
private fun sendTokenToServer(token: String) { /* ... */ }
private fun showNotification(title: String, body: String) { /* ... */ }
}Registering the Service
Declare your service in the manifest so Android can deliver messages to it. The MESSAGING_EVENT intent filter is required.
<!-- AndroidManifest.xml inside <application> -->
<service
android:name=".MyFcmService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>Notification vs Data Messages
FCM messages come in two flavors:
- Notification messages — FCM auto-displays them in the tray when the app is in the background;
onMessageReceivedonly fires when the app is in the foreground. - Data messages — always delivered to
onMessageReceivedas a key/value map so you control the handling.
Read custom fields from message.data.
import com.google.firebase.messaging.RemoteMessage
fun handle(message: RemoteMessage) {
val type = message.data["type"] // your custom field
val itemId = message.data["itemId"]
when (type) {
"chat" -> openChat(itemId)
"promo" -> openPromo(itemId)
}
}
fun openChat(id: String?) {}
fun openPromo(id: String?) {}Building a Notification Channel
Since Android 8, every notification needs a channel. Create it once at startup; the system uses the channel to control sound, importance and the user's per-channel settings.
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
fun createChannel(context: Context) {
val channel = NotificationChannel(
"messages",
"Messages",
NotificationManager.IMPORTANCE_HIGH
)
val manager = context.getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
}Showing the Notification
Build the notification with NotificationCompat.Builder, tied to your channel id, then post it with NotificationManagerCompat.
Remember: on API 33+ this only appears if the user granted POST_NOTIFICATIONS.
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
fun showNotification(context: Context, title: String, body: String) {
val notification = NotificationCompat.Builder(context, "messages")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(context).notify(1, notification)
}Topic Subscriptions
Instead of tracking individual tokens, you can broadcast to a topic. Clients subscribe to a topic name, and your server sends one message to everyone subscribed.
Great for things like news, sports or all-users announcements.
import com.google.firebase.Firebase
import com.google.firebase.messaging.messaging
import kotlinx.coroutines.tasks.await
suspend fun subscribeToNews() {
Firebase.messaging.subscribeToTopic("news").await()
}
suspend fun unsubscribeFromNews() {
Firebase.messaging.unsubscribeFromTopic("news").await()
}Quick Check
Your app is in the background and receives a pure notification message from FCM. What happens?
Recap: Cloud Messaging
You can now reach users with push notifications:
- Add
firebase-messagingand request POST_NOTIFICATIONS on API 33+. - Each install has an FCM token; upload it to your server.
- Extend
FirebaseMessagingServiceand overrideonMessageReceived/onNewToken. - Know the difference between notification and data messages.
- Create a notification channel, build with
NotificationCompat, or broadcast via topics.
That completes the Firebase trio: Auth, Firestore and Messaging — a full backend for your Android app.
Frequently asked questions
Is the “Push with Cloud Messaging” lesson free?
Yes — the full text of “Push with Cloud Messaging” is free to read here on the web, and the Android Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Android Academy course, upgrade to CoddyKit PRO.
What will I learn in “Push with Cloud Messaging”?
Send and receive FCM notifications. You practise Android Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Android Academy?
No prior experience is required. Android Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Push with Cloud Messaging” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Android Academy lesson?
Yes. Every Android Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Setting Up Firebase
- Firebase Authentication
- Cloud Firestore Basics
- Push with Cloud Messaging