Push Notifications
Push notifications re-engage users with timely updates, but they're one of the trickier mobile features to get right: messages travel through platform services (FCM/APNs), permission must be requested thoughtfully, and your app has to handle notifications in three different states — foreground, background, and killed — each behaving differently. And they must be tested on real devices, since simulators have limitations.
The cross-platform standard is Firebase Cloud Messaging (FCM), which routes to Apple's APNs on iOS and Google's infrastructure on Android. The three-state handling is the part most teams underestimate — a notification that opens the right screen from a killed app is meaningfully harder than one shown while the app is open.
TL;DR
- Use Firebase Cloud Messaging (FCM) for cross-platform.
- Request permission at the right moment, not on first launch.
- Handle foreground, background, and killed states.
- Test on real devices — simulators have limitations.
Quick Example
Request permission, then register the device's FCM token with your server:
Core Concepts
Notification types: remote/push (sent from a server via FCM/APNs), local (scheduled by the app), data (silent, triggers code without UI), and display (shows notification UI).
The flow and the three app states:
React Native Setup
Configure native projects: iOS — enable Push Notifications capability, add an APNs key, and GoogleService-Info.plist; Android — add google-services.json and the Google Services Gradle plugin.
Then handle all three states:
Flutter Setup
Local Notifications
For reminders and scheduled alerts, no server needed:
Best Practices
- Ask permission at the right moment — after showing value, not on first launch.
- Send relevant, timely notifications; let users customize preferences and respect quiet hours.
- Handle all three app states and route taps to the right screen via the notification's data (deep linking).
- Register and refresh tokens on your server; tokens rotate.
- Test on real devices — push behavior differs from simulators.
Common Mistakes
Requesting permission on first launch
Ignoring the killed/background states
FAQ
What's the difference between FCM and APNs?
APNs (Apple Push Notification service) is Apple's low-level delivery system for iOS; FCM (Firebase Cloud Messaging) is Google's cross-platform service that delivers to Android directly and to iOS by relaying through APNs. Using FCM gives you one API and one server integration for both platforms — which is why it's the common choice. On iOS you still configure APNs credentials so FCM can deliver through it.
Why do I have to handle three app states separately?
Because the OS treats notifications differently depending on whether your app is in the foreground, background, or killed. In the foreground, no system notification appears automatically — you decide whether/how to show it. In the background, the system displays it and your handler runs on tap. From killed, tapping cold-starts the app and you must check for the launching notification explicitly. Handling only the foreground case (the easy one) breaks taps from the other two states.
When should I ask for notification permission?
Not on first launch. Ask after the user has experienced enough value to want notifications — e.g. after they create something that warrants updates — ideally preceded by a custom pre-prompt explaining the benefit. On iOS especially, a denial is sticky (the user must change it in Settings), so a poorly-timed request permanently loses that channel. Earn the permission rather than demanding it upfront.
Why must I test push notifications on real devices?
Simulators and emulators have real limitations — iOS Simulator historically couldn't receive remote pushes at all (newer versions have partial support), and behavior around background/killed states, token generation, and delivery timing differs from hardware. Since the three-state handling and platform delivery are exactly what you need to verify, a real device is the only reliable test. Always validate the full flow (server → device → tap → correct screen) on hardware.
Related Topics
- React Native — React Native development
- Flutter — Flutter development
- Mobile Navigation — Deep linking from notifications
- Mobile State Management — App state
- Expo — Expo's notifications API