| name | push-notification-setup |
| description | Implement push notifications for iOS and Android. Covers Firebase Cloud Messaging, Apple Push Notification service, handling notifications, and backend integration. |
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: , ) }.joined()
()
saveTokenToBackend(token: token)
}
(
: ,
:
) {
()
}
(
: ,
: ,
:
() ->
) {
userInfo notification.request.content.userInfo
( , ) {
completionHandler([.banner, .sound, .badge])
} {
completionHandler([.sound, .badge])
}
handlePushNotification(userInfo)
}
(
: ,
: ,
: () ->
) {
userInfo response.notification.request.content.userInfo
handlePushNotification(userInfo)
completionHandler()
}
( : [: ]) {
deepLink userInfo[] {
.default.post(
name: .(),
object: deepLink
)
}
}
(: ) {
urlString
url (string: urlString) { }
request (url: url)
request.httpMethod
request.setValue(, forHTTPHeaderField: )
body: [: ] [: token, : ]
request.httpBody .data(withJSONObject: body)
.shared.dataTask(with: request).resume()
}
}
3. Android Setup with Kotlin
<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"] ?: ""
(remoteMessage.notification != ) {
showNotification(title, body, deepLink)
}
}
{
channelId =
createNotificationChannel(channelId)
intent = Intent(, MainActivity::.java).apply {
(deepLink.isNotEmpty()) {
= android.net.Uri.parse(deepLink)
}
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
pendingIntent = PendingIntent.getActivity(
, , intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
notification = NotificationCompat.Builder(, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel()
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
notificationManager = getSystemService(NOTIFICATION_SERVICE) NotificationManager
notificationManager.notify(System.currentTimeMillis().toInt(), notification)
}
{
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channel = NotificationChannel(
channelId,
,
NotificationManager.IMPORTANCE_DEFAULT
)
notificationManager = getSystemService(NOTIFICATION_SERVICE) NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
{
println()
}
}
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