ā–„NYC
skills/aj-geddes/useful-ai-prompts/push-notification-setup

push-notification-setup

SKILL.md

Push Notification Setup

Overview

Implement comprehensive push notification systems for iOS and Android applications using Firebase Cloud Messaging and native platform services.

When to Use

  • Sending real-time notifications to users
  • Implementing user engagement features
  • Deep linking from notifications to specific screens
  • Handling silent/background notifications
  • Tracking notification analytics

Instructions

1. Firebase Cloud Messaging Setup

import messaging from '@react-native-firebase/messaging';
import { Platform } from 'react-native';

export async function initializeFirebase() {
  try {
    if (Platform.OS === 'ios') {
      const permission = await messaging().requestPermission();
      if (permission === messaging.AuthorizationStatus.AUTHORIZED) {
        console.log('iOS notification permission granted');
      }
    }

    const token = await messaging().getToken();
    console.log('FCM Token:', token);
    await saveTokenToBackend(token);

    messaging().onTokenRefresh(async (newToken) => {
      await saveTokenToBackend(newToken);
    });

    messaging().onMessage(async (remoteMessage) => {
      console.log('Notification received:', remoteMessage);
      showLocalNotification(remoteMessage);
    });

    messaging().setBackgroundMessageHandler(async (remoteMessage) => {
      if (remoteMessage.data?.type === 'sync') {
        syncData();
      }
    });

    messaging()
      .getInitialNotification()
      .then((remoteMessage) => {
        if (remoteMessage) {
          handleNotificationOpen(remoteMessage);
        }
      });

    messaging().onNotificationOpenedApp((remoteMessage) => {
      handleNotificationOpen(remoteMessage);
    });
  } catch (error) {
    console.error('Firebase initialization failed:', error);
  }
}

export async function saveTokenToBackend(token) {
  try {
    const response = await fetch('https://api.example.com/device-tokens', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        token,
        platform: Platform.OS,
        timestamp: new Date().toISOString()
      })
    });
    if (!response.ok) {
      console.error('Failed to save token');
    }
  } catch (error) {
    console.error('Error saving token:', error);
  }
}

function handleNotificationOpen(remoteMessage) {
  const { data } = remoteMessage;
  if (data?.deepLink) {
    navigationRef.navigate(data.deepLink, JSON.parse(data.params || '{}'));
  }
}

2. iOS Native Setup with Swift

import UIKit
import UserNotifications

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    requestNotificationPermission()

    if let remoteNotification = launchOptions?[.remoteNotification] as? [AnyHashable: Any] {
      handlePushNotification(remoteNotification)
    }

    return true
  }

  func requestNotificationPermission() {
    UNUserNotificationCenter.current().requestAuthorization(
      options: [.alert, .sound, .badge]
    ) { granted, error in
      if granted {
        DispatchQueue.main.async {
          UIApplication.shared.registerForRemoteNotifications()
        }
      }
    }
  }

  func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
  ) {
    let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
    print("Device Token: \(token)")
    saveTokenToBackend(token: token)
  }

  func application(
    _ application: UIApplication,
    didFailToRegisterForRemoteNotificationsWithError error: Error
  ) {
    print("Failed to register: \(error)")
  }

  func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    willPresent notification: UNNotification,
    withCompletionHandler completionHandler:
      @escaping (UNNotificationPresentationOptions) -> Void
  ) {
    let userInfo = notification.request.content.userInfo
    if #available(iOS 14.0, *) {
      completionHandler([.banner, .sound, .badge])
    } else {
      completionHandler([.sound, .badge])
    }
    handlePushNotification(userInfo)
  }

  func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
  ) {
    let userInfo = response.notification.request.content.userInfo
    handlePushNotification(userInfo)
    completionHandler()
  }

  private func handlePushNotification(_ userInfo: [AnyHashable: Any]) {
    if let deepLink = userInfo["deepLink"] as? String {
      NotificationCenter.default.post(
        name: NSNotification.Name("openDeepLink"),
        object: deepLink
      )
    }
  }

  private func saveTokenToBackend(token: String) {
    let urlString = "https://api.example.com/device-tokens"
    guard let url = URL(string: urlString) else { return }

    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")

    let body: [String: Any] = ["token": token, "platform": "ios"]
    request.httpBody = try? JSONSerialization.data(withJSONObject: body)

    URLSession.shared.dataTask(with: request).resume()
  }
}

3. Android Setup with Kotlin

// AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  <application>
    <service
      android:name=".services.MyFirebaseMessagingService"
      android:exported="false">
      <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
      </intent-filter>
    </service>
  </application>
</manifest>

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class MyFirebaseMessagingService : FirebaseMessagingService() {
  override fun onNewToken(token: String) {
    super.onNewToken(token)
    println("FCM Token: $token")
    saveTokenToBackend(token)
  }

  override fun onMessageReceived(remoteMessage: RemoteMessage) {
    super.onMessageReceived(remoteMessage)

    val title = remoteMessage.notification?.title ?: "Notification"
    val body = remoteMessage.notification?.body ?: ""
    val deepLink = remoteMessage.data["deepLink"] ?: ""

    if (remoteMessage.notification != null) {
      showNotification(title, body, deepLink)
    }
  }

  private fun showNotification(title: String, message: String, deepLink: String = "") {
    val channelId = "default_channel"
    createNotificationChannel(channelId)

    val intent = Intent(this, MainActivity::class.java).apply {
      if (deepLink.isNotEmpty()) {
        data = android.net.Uri.parse(deepLink)
      }
      addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
    }

    val pendingIntent = PendingIntent.getActivity(
      this, 0, intent,
      PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

    val notification = NotificationCompat.Builder(this, channelId)
      .setSmallIcon(R.drawable.ic_notification)
      .setContentTitle(title)
      .setContentText(message)
      .setAutoCancel(true)
      .setContentIntent(pendingIntent)
      .setPriority(NotificationCompat.PRIORITY_DEFAULT)
      .build()

    val notificationManager = getSystemService(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 Channel",
        NotificationManager.IMPORTANCE_DEFAULT
      )
      val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
      notificationManager.createNotificationChannel(channel)
    }
  }

  private fun saveTokenToBackend(token: String) {
    println("Saving token to backend: $token")
  }
}

4. Flutter Implementation

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';

class NotificationHandler {
  static Future<void> initialize(NavigatorState navigator) async {
    final settings = await FirebaseMessaging.instance.requestPermission(
      alert: true,
      sound: true,
      badge: true,
    );

    if (settings.authorizationStatus == AuthorizationStatus.authorized) {
      print('Notification permission granted');
    }

    final token = await FirebaseMessaging.instance.getToken();
    print('FCM Token: $token');

    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('Received: ${message.notification?.title}');
    });

    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      _handleDeepLink(navigator, message.data);
    });

    final initialMessage = await FirebaseMessaging.instance.getInitialMessage();
    if (initialMessage != null) {
      _handleDeepLink(navigator, initialMessage.data);
    }
  }

  static void _handleDeepLink(NavigatorState navigator, Map<String, dynamic> data) {
    final deepLink = data['deepLink'] as String?;
    if (deepLink != null) {
      navigator.pushNamed(deepLink);
    }
  }
}

Best Practices

āœ… DO

  • Request permission before sending notifications
  • Implement token refresh handling
  • Use different notification channels by priority
  • Validate tokens regularly
  • Track notification delivery
  • Implement deep linking
  • Handle notifications in all app states
  • Use silent notifications for data sync
  • Store tokens securely on backend
  • Provide user notification preferences
  • Test on real devices

āŒ DON'T

  • Send excessive notifications
  • Send without permission
  • Store tokens insecurely
  • Ignore notification failures
  • Send sensitive data in payload
  • Use notifications for spam
  • Forget to handle background notifications
  • Make blocking calls in handlers
  • Send duplicate notifications
  • Ignore user preferences
Weekly Installs
99
First Seen
Jan 21, 2026
Installed on
claude-code80
opencode79
gemini-cli70
codex68
antigravity60
cursor60