FCM with Flutter
Complete guide to sending and receiving FCM push notifications in Flutter apps.
Setup
1. Install the Plugin
From the root of your Flutter project, run:
bashflutter pub add firebase_messaging
If you haven't already, also add firebase_core and run flutterfire configure to generate your Firebase config:
bashflutter pub add firebase_core dart pub global activate flutterfire_cli flutterfire configure
This generates a firebase_options.dart file with your project config. On Android it also adds google-services.json, and on iOS it adds GoogleService-Info.plist.
2. Initialize Firebase
dartimport 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'firebase_options.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); runApp(MyApp()); }
3. Get the Device Token
dartfinal messaging = FirebaseMessaging.instance; // Request permission (required on iOS, Android 13+) final settings = await messaging.requestPermission( provisional: true, // lets user choose notification type on first receive ); // On iOS, ensure APNs token is available before getting FCM token final apnsToken = await messaging.getAPNSToken(); if (apnsToken != null || !Platform.isIOS) { final token = await messaging.getToken(); print('FCM Token: $token'); }
iOS note: In iOS SDK 10.4.0+, the APNs token must be available before making FCM API requests. Always check
getAPNSToken()before callinggetToken()on iOS.
4. Handle Foreground Messages
dartFirebaseMessaging.onMessage.listen((RemoteMessage message) { print('Got a message in foreground!'); print('Title: ${message.notification?.title}'); print('Body: ${message.notification?.body}'); print('Data: ${message.data}'); });
5. Handle Background Messages
dart// This must be a top-level function @pragma('vm:entry-point') Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(); print('Background message: ${message.messageId}'); } void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); runApp(MyApp()); }
Listen for Token Refresh
FCM tokens can change. Subscribe to the refresh stream to keep your server in sync:
dartFirebaseMessaging.instance.onTokenRefresh.listen((newToken) { // Send the new token to your server print('Token refreshed: $newToken'); });
Topic Subscription
dart// Subscribe await FirebaseMessaging.instance.subscribeToTopic('news'); // Unsubscribe await FirebaseMessaging.instance.unsubscribeFromTopic('news');
Testing Your Setup
- Copy your device token from the debug console
- Go to the FCM Tester
- Paste your service account JSON
- Select "Device Token" and paste the token
- Send a test notification
Common Issues
| Issue | Fix |
|---|---|
| Token is null | Ensure Firebase is initialized and permissions are granted. On iOS, check that the APNs token is available first |
| No notification in foreground | Foreground messages don't show automatically — use a local notification plugin |
| Background handler not firing | Make sure the handler is a top-level function with @pragma('vm:entry-point') |
| iOS not receiving | Check APNs key is uploaded in Firebase Console, and that flutterfire configure was run |
| Android 13+ not receiving | Request POST_NOTIFICATIONS permission — on Android 13+ it's required at runtime |
| Hot reload doesn't apply plugin changes | Native plugin changes require a full rebuild (flutter run) |
Related
Was this page helpful?