Simplify iOS Push Notifications With Flutter & Firebase
If you’re looking to get Flutter iOS Firebase push notifications up and running without a headache, you’re in the right place. Over the past few years, Firebase has become the de‑facto backend for many mobile apps, and its Cloud Messaging service (FCM) works surprisingly well with Flutter’s cross‑platform codebase. The trickiest part is usually the iOS side—certificates, provisioning profiles, and the occasional Apple‑specific quirk. This guide walks you through the whole process, from Firebase console setup to handling a notification when the app is in the foreground.
Setting Up Firebase for Your iOS Project
Before you write any Dart code, you need a Firebase project that knows about your iOS bundle identifier.
- Head to the Firebase console and click “Add app”. Choose iOS and enter the exact bundle ID you use in Xcode.
- Download the generated
GoogleService-Info.plistfile. Drag it into theRunnerfolder of your Flutter project, making sure to select “Copy items if needed”. - In the console, enable “Cloud Messaging”. This will create the APNs authentication key you’ll later upload to Apple.
Apple now prefers an APNs authentication key over the older certificate method. In your Apple Developer account, go to “Certificates, Identifiers & Profiles”, create a new key, check “Apple Push Notification service (APNs)”, and download the .p8 file. Back in Firebase, upload that key under Project Settings → Cloud Messaging.
Integrating the Flutter Firebase Messaging Plugin
With the backend ready, add the official plugin to your pubspec.yaml:
dependencies:firebase_messaging: ^14.6.0
Run flutter pub get, then open ios/Runner.xcworkspace in Xcode. Two small adjustments are required:
- Set
Push NotificationsandBackground Modes → Remote notificationsto “Enabled” in the project’s Signing & Capabilities tab. - Update the
Info.plistwith a usage description, for example:<key>FirebaseMessagingAutoInitEnabled</key><true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Now initialize the plugin in your Dart entry point, usually main.dart:
void main() async {WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging messaging = FirebaseMessaging.instance;
// Request permission on iOS
NotificationSettings settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
runApp(MyApp());
}
Handling Notifications in the App
FCM can deliver three kinds of messages: data‑only, notification‑only, and combined. iOS treats notification‑only payloads as system alerts, while data‑only messages are delivered directly to the app code.
To react to a message when the app is in the foreground, attach a listener:
FirebaseMessaging.onMessage.listen((RemoteMessage message) {// Show a custom in‑app alert or update UI
print('Received a foreground message: \${message.messageId}');
});
When the user taps a notification and the app launches from a terminated state, you can capture the initial message:
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();Both listeners return a RemoteMessage object, which contains data (your custom key‑value pairs) and notification (title, body, image, etc.). It’s good practice to centralize this handling in a service class so the UI layer stays clean.
Badge Management
iOS badges don’t update automatically with FCM. After processing a message, call:
await FirebaseMessaging.instance.setBadgeCount(newCount);Remember to clear the badge when the user opens the app, otherwise the number will stick.
Testing Push Notifications on a Real Device
Simulator testing is limited—Apple’s push service won’t deliver to the iOS simulator. You’ll need a physical iPhone, registered in your Apple Developer portal.
- Build and run the Flutter app on the device via
flutter run. - Open the Firebase console, navigate to Cloud Messaging, and click “Send a test message”. Paste the device’s FCM token (obtainable with
messaging.getToken()) into the “Target” field. - Choose a simple payload, like a title and body, then hit “Test”. The notification should appear instantly.
If nothing shows up, double‑check that:
- The APNs key uploaded to Firebase matches the bundle ID.
- Push capability is enabled in Xcode.
- Device is not in “Do Not Disturb” mode.
Common Pitfalls and How to Avoid Them
Even after following the steps above, developers often stumble on a few recurring issues.
- Token changes on reinstall. Store the token in a secure backend and update it whenever
onTokenRefreshfires. - Silent notifications being dropped. iOS requires the
content‑available: 1flag and the “Remote notifications” background mode enabled. - Incorrect payload format. For combined messages, place the
notificationobject at the top level anddataunderdata. Misplacing keys can cause the system to ignore the message.
Wrapping Up the Essentials
Putting Flutter iOS Firebase push notifications together isn’t magic; it’s a series of predictable configurations. Once your Firebase project, Apple credentials, and Flutter plugin are aligned, sending a test message feels almost like sending an email. The real power comes when you start using data‑only payloads to drive in‑app experiences—think personalized offers or real‑time chat alerts—without ever showing a system banner.
FAQ
Do I need an Apple Developer Program membership to use push notifications?
Yes. Even though the APNs authentication key is free to generate, you must be enrolled in the Apple Developer Program to access the Certificates, Identifiers & Profiles portal.
Can I use the same Firebase project for both Android and iOS?
Absolutely. Add an Android app alongside your iOS app in the Firebase console, and the same Cloud Messaging project will handle both platforms.
What’s the difference between a data‑only and a notification‑only message?
A notification‑only message is displayed by iOS automatically, while a data‑only message is delivered straight to your Flutter code, giving you full control over UI and behavior.
How often does the FCM token change?
The token can change when the app is reinstalled, the user restores a device, or after a period of inactivity. Listen to FirebaseMessaging.onTokenRefresh and update your backend each time.