Push Notifications: iOS and Android Implementation Guide
Push notifications are one of the most effective tools for user engagement and retention. According to research from Localytics, apps that use push notifications see 88% higher engagement rates and 2-3x better retention compared to apps that do not. A well-timed, relevant notification can bring users back to your app, inform them of important updates, and drive conversions.
However, poorly implemented notifications annoy users and lead to high opt-out rates — 60% of users opt out of push within the first week if they find them irrelevant. Apple’s Human Interface Guidelines and Google’s Material Design documentation both emphasize that push notifications must provide clear, immediate value to users. This guide covers the complete technical implementation and strategic best practices for push notifications on iOS and Android.
How Push Notifications Work
Push notifications follow a standard delivery pipeline. A server (your backend) sends a notification request to the platform’s notification service. The service delivers the notification to the device. The operating system displays it to the user, potentially waking the app or showing the notification in the notification center.
Apple uses the Apple Push Notification service (APNs), which supports HTTP/2 multiplexed connections for efficient server-to-device delivery. Android uses Firebase Cloud Messaging (FCM), which also supports iOS, web, and desktop through a single API. FCM can deliver notifications through APNs on iOS devices, providing a unified API across platforms.
Firebase Cloud Messaging (FCM)
FCM is the recommended cross-platform solution because it provides a unified API for both iOS and Android, handles token management, and integrates with Firebase Analytics for notification engagement tracking.
Setup and Token Registration
Add Firebase to your Android project and include the Firebase messaging dependency. Each app installation receives a unique registration token. Send this token to your server to enable targeting:
class MyFirebaseService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
// Send token to your app server
sendTokenToServer(token)
}
---On iOS, FCM uses APNs under the hood. You must register for remote notifications and pass the APNs device token to FCM through the apnsToken property.
Sending Notifications via FCM
FCM supports two payload types. The notification payload is displayed automatically by the system. The data payload is delivered to your app for custom processing — use it for deep linking, in-app display, and background processing:
{
"to": "device_token",
"notification": {
"title": "New Message",
"body": "You have a new message from Alice"
},
"data": {
"conversation_id": "123",
"type": "direct_message"
}
---For topic-based messaging, subscribe users to topics and send to the topic name instead of individual tokens. Topics support unlimited subscribers and are ideal for broadcast notifications like breaking news or promotions.
Android Notification Channels
Android 8.0 (API 26) introduced notification channels. Every notification must belong to a channel, and users can configure channel-specific behavior — importance, sound, vibration, and lock screen visibility:
val channel = NotificationChannel(
"messages",
"Messages",
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "Direct messages from other users"
enableVibration(true)
setShowBadge(true)
---Define channels for each notification category: messages, updates, promotional, and system. Users who find promotional notifications annoying can disable that channel without losing critical message notifications. This granular control significantly reduces overall opt-out rates.
Apple Push Notification Service (APNs)
APNs delivers notifications to all Apple platforms — iOS, macOS, watchOS, and tvOS. The protocol uses HTTP/2 with TLS for efficient, multiplexed connections. APNs supports two authentication methods: token-based (recommended) and certificate-based.
Registration and Permission
Request permission at a meaningful moment, not immediately on first launch. Use the pre-prompt pattern where you explain the value before showing the system dialog:
import UserNotifications
UNUserNotificationCenter.current().requestAuthorization(
options: [.alert, .sound, .badge]
) { granted, error in
guard granted else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
---APNs Payload and Rich Media
APNs supports notification service extensions for content modification before display. Use mutable-content: 1 in the payload to enable extensions. Service extensions can download and attach images, decrypt encrypted content, or modify the notification based on user preferences:
{
"aps": {
"alert": {
"title": "Order Shipped",
"subtitle": "Order #12345",
"body": "Your package has been shipped and will arrive tomorrow"
},
"sound": "default",
"badge": 3,
"mutable-content": 1,
"category": "order_update"
},
"order_id": "12345",
"media_url": "https://example.com/package_photo.jpg"
---Notification Actions and Categories
iOS supports interactive notifications with action buttons. Define categories with associated actions in your app’s notification content extension. Users can reply to messages, mark tasks complete, or snooze reminders without opening the app.
Deep Linking from Notifications
Every notification should deep-link to the most relevant screen in your app. This is the primary mechanism by which notifications drive engagement:
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
let userInfo = response.notification.request.content.userInfo
if let orderId = userInfo["order_id"] as? String {
navigateToOrderDetail(orderId: orderId)
}
completionHandler()
---On Android, extract deep link data from the intent extras. Use Android’s deep linking with intent filters to handle both notification-driven and direct URL-driven deep linking uniformly:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
intent?.extras?.getString("order_id")?.let { orderId ->
navigateToOrderDetail(orderId)
}
}
---Permission Strategy
The timing of your permission request is critical. Requesting notification permission immediately on first launch leads to high denial rates — users have not yet experienced enough value to grant access.
Instead, use a two-step approach. First, show an in-app prompt explaining the value (e.g., “Get notified when your order ships”), with a “Continue” button that triggers the system permission dialog. According to industry data, this pre-prompt approach achieves 60-80% opt-in rates compared to 30-50% for immediate requests.
For users who initially deny permission, use a soft re-prompt after they have experienced more app value. On iOS, you cannot re-request permission programmatically — navigate the user to Settings. On Android 13+, you can request permission again at a more opportune moment.
Best Practices for Engagement
Personalize notifications with the user’s name or relevant content. Use notification channels on Android to let users control notification types by category. Group related notifications on iOS using thread identifiers to prevent notification overload.
Respect quiet hours — a notification sent at 3 AM is more likely to result in opt-out than engagement. Use timezone-aware scheduling and consider the user’s historical engagement times.
A/B test notification copy, timing, and frequency. Measure open rates, opt-out rates, and conversion metrics to optimize your notification strategy. A well-optimized notification strategy can achieve open rates of 15-25% for personalized messages, compared to 2-5% for generic broadcast notifications.
Notification Analytics Integration
Track notification delivery, tap, and conversion events in your analytics platform. Firebase Analytics automatically tracks notification open events when sent through FCM. Use UTM parameters in deep links to track notification-driven conversions in Google Analytics.
FAQ
How do I handle notification tokens when users reinstall?
FCM and APNs generate new tokens when apps are reinstalled. Old tokens become invalid and the delivery services return error responses. Implement a server-side token refresh mechanism where the app sends its current token on every launch. Periodically purge invalid tokens based on FCM and APNs error responses.
What is the maximum payload size for push notifications?
APNs allows 4 KB for the total payload. FCM allows up to 4 KB for notification payloads and 2 KB for data payloads on Android (4 KB for iOS via FCM). Keep payloads minimal — the notification title and body should be enough to convey value. Use data payload fields for identifiers and URLs, not full content.
Can I send notifications without user permission?
On iOS, you must have user permission for alert notifications. Critical alerts (medical, security) can bypass the ringer switch and require special entitlement from Apple. On Android, notification permission is optional for apps targeting Android 13+, and you must request it to send notifications. On older Android versions, notifications are enabled by default.
What is the difference between local and push notifications?
Local notifications are scheduled and delivered by the device itself — no server or internet connection required. Push notifications are sent from a server through APNs or FCM. Local notifications are ideal for timers, alarms, and reminders. Push notifications are necessary for real-time events like messages, order updates, and breaking news.
How do I send notifications to specific user segments?
Use topics in FCM for broad segments (all users, premium users, users in a specific country). For precise targeting, maintain user-token mappings on your server and send to specific token lists. Use FCM’s condition parameter to target combinations of topics and user properties.
Conclusion
Push notifications are a powerful engagement tool when implemented correctly. Use FCM for cross-platform simplicity, deep-link every notification to relevant content, ask for permission at the right moment, and continuously optimize based on engagement metrics. Remember that push notification access is a privilege — every notification should provide clear value to the user. Respect notification channels, personalize content, and respect user preferences to maintain high opt-in rates and drive meaningful engagement.
For related topics, explore Mobile App Analytics Guide and Offline Mobile Apps Guide.