
Push Notifications
- 20 installs
- 60 repo stars
- Updated June 14, 2026
- ahmed3elshaer/everything-claude-code-mobile
push-notifications is a Claude Code skill that provides push notification patterns including FCM setup for Android, APNs for iOS, notification channels, and payload handling.
About
push-notifications is a Claude Code skill that documents push notification patterns for mobile apps. It covers Firebase Cloud Messaging setup for Android, a FirebaseMessagingService that routes messages by type, notification channels for Android 8+, and the difference between data and notification messages across foreground and background. Developers use it when integrating FCM (and APNs for iOS) into an app. Rich notifications and payload handling are included.
- Firebase Cloud Messaging setup and FirebaseMessagingService handling
- Notification channels for Android 8+ with per-type importance
- Data vs notification message behavior across foreground and background
Push Notifications by the numbers
- 20 all-time installs (skills.sh)
- Ranked #761 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
push-notifications capabilities & compatibility
- Capabilities
- push notifications · fcm integration · notification channels
- Works with
- github
- Use cases
- frontend
What push-notifications says it does
Data messages always arrive here
npx skills add https://github.com/ahmed3elshaer/everything-claude-code-mobile --skill push-notificationsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 20 |
|---|---|
| repo stars | ★ 60 |
| Last updated | June 14, 2026 |
| Repository | ahmed3elshaer/everything-claude-code-mobile ↗ |
What it does
Integrate push notifications via Firebase Cloud Messaging (and APNs) with channels, payload routing, and foreground/background handling.
Who is it for?
Integrating Firebase Cloud Messaging push notifications into an Android app
Skip if: Non-push in-app messaging or notification analytics
When should I use this skill?
Adding push notifications, notification channels, or payload routing to a mobile app
What you get
The app receives and routes FCM messages, defines Android channels, and handles foreground and background delivery
By the numbers
- Defines 3 notification channels (default, chat, promotions)
Files
Push Notification Patterns
Android / Firebase Cloud Messaging
Firebase Setup
Add google-services.json to the app/ directory and configure dependencies:
// build.gradle.kts (project)
plugins {
id("com.google.gms.google-services") version "4.4.0" apply false
}
// build.gradle.kts (app)
plugins {
id("com.google.gms.google-services")
}
dependencies {
implementation(platform("com.google.firebase:firebase-bom:32.7.0"))
implementation("com.google.firebase:firebase-messaging-ktx")
}FirebaseMessagingService Implementation
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
// Send token to your server for targeting
TokenRepository.syncTokenToServer(token)
}
override fun onMessageReceived(message: RemoteMessage) {
// Data messages always arrive here
val data = message.data
val title = data["title"] ?: message.notification?.title ?: return
val body = data["body"] ?: message.notification?.body ?: ""
when (data["type"]) {
"chat" -> showChatNotification(title, body, data)
"promo" -> showPromoNotification(title, body, data)
else -> showDefaultNotification(title, body)
}
}
private fun showDefaultNotification(title: String, body: String) {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(this, CHANNEL_DEFAULT)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(body)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.notify(System.currentTimeMillis().toInt(), notification)
}
companion object {
const val CHANNEL_DEFAULT = "default"
const val CHANNEL_CHAT = "chat_messages"
const val CHANNEL_PROMO = "promotions"
}
}Notification Channels (Android 8+)
object NotificationChannels {
fun createAll(context: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val manager = context.getSystemService(NotificationManager::class.java)
val defaultChannel = NotificationChannel(
"default",
"General",
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "General notifications"
}
val chatChannel = NotificationChannel(
"chat_messages",
"Chat Messages",
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "New chat messages"
enableVibration(true)
enableLights(true)
}
val promoChannel = NotificationChannel(
"promotions",
"Promotions",
NotificationManager.IMPORTANCE_LOW
).apply {
description = "Promotional offers and deals"
}
manager.createNotificationChannels(listOf(defaultChannel, chatChannel, promoChannel))
}
}Call NotificationChannels.createAll(this) in Application.onCreate().
Data vs Notification Messages
| Aspect | Notification Message | Data Message |
|---|---|---|
| Foreground | onMessageReceived | onMessageReceived |
| Background | System tray (auto) | onMessageReceived |
| Customizable | Limited | Full control |
| Payload key | "notification": {} | "data": {} |
Best practice: Use data-only messages for full control over display behavior.
Token Registration and Server Sync
class TokenRepository(private val api: ApiService) {
suspend fun syncTokenToServer(token: String) {
val deviceInfo = DeviceInfo(
token = token,
platform = "android",
appVersion = BuildConfig.VERSION_NAME,
locale = Locale.getDefault().toLanguageTag()
)
api.registerPushToken(deviceInfo)
}
suspend fun getAndSyncToken() {
val token = FirebaseMessaging.getInstance().token.await()
syncTokenToServer(token)
}
}Notification Permission (Android 13+)
val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// Permission granted, sync token
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}---
iOS / APNs
Push Notification Capability
Enable in Xcode: Target > Signing & Capabilities > + Push Notifications. Also enable Background Modes > Remote notifications.
UNUserNotificationCenter Setup and Permissions
import UserNotifications
final class NotificationManager: NSObject, UNUserNotificationCenterDelegate {
static let shared = NotificationManager()
func requestAuthorization() async -> Bool {
let center = UNUserNotificationCenter.current()
center.delegate = self
do {
let granted = try await center.requestAuthorization(
options: [.alert, .badge, .sound, .provisional]
)
if granted {
await MainActor.run {
UIApplication.shared.registerForRemoteNotifications()
}
}
return granted
} catch {
return false
}
}
// Foreground notification display
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification
) async -> UNNotificationPresentationOptions {
return [.banner, .badge, .sound]
}
// Notification tap handling
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse
) async {
let userInfo = response.notification.request.content.userInfo
handleNotificationPayload(userInfo)
}
private func handleNotificationPayload(_ userInfo: [AnyHashable: Any]) {
guard let type = userInfo["type"] as? String else { return }
switch type {
case "chat":
let chatId = userInfo["chat_id"] as? String ?? ""
DeepLinkRouter.shared.destination = .chat(id: chatId)
case "product":
let productId = userInfo["product_id"] as? String ?? ""
DeepLinkRouter.shared.destination = .product(id: productId)
default:
break
}
}
}AppDelegate Registration
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
Task { await TokenService.shared.syncToken(token) }
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
print("Push registration failed: \(error.localizedDescription)")
}Notification Service Extension (Rich Notifications)
Create a new target: File > New > Target > Notification Service Extension.
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
guard let content = bestAttemptContent,
let imageURLString = content.userInfo["image_url"] as? String,
let imageURL = URL(string: imageURLString) else {
contentHandler(request.content)
return
}
downloadImage(from: imageURL) { attachment in
if let attachment = attachment {
content.attachments = [attachment]
}
contentHandler(content)
}
}
override func serviceExtensionTimeWillExpire() {
if let content = bestAttemptContent {
contentHandler?(content)
}
}
}Provisional Authorization (iOS 12+)
Provisional auth delivers notifications quietly to Notification Center without prompting:
let granted = try await center.requestAuthorization(options: [.alert, .sound, .provisional])Users can then promote to prominent delivery or turn off from the notification itself.
---
Testing
# Android - send test via Firebase CLI
firebase messaging:send --project=my-project --json '{
"message": {
"token": "DEVICE_TOKEN",
"data": { "type": "chat", "title": "Test", "body": "Hello" }
}
}'
# iOS - local notification for testing UI
let content = UNMutableNotificationContent()
content.title = "Test Notification"
content.body = "This is a local test."
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "test", content: content, trigger: trigger)
try await UNUserNotificationCenter.current().add(request)Related skills
FAQ
Where do data messages arrive?
Data messages always arrive in onMessageReceived in both foreground and background, unlike notification messages backgrounded to the system tray.
Are notification channels required?
On Android 8+ yes; the skill creates default, chat, and promotions channels with different importance levels.