To start using the Cloud Messaging package within your project, import it at the top of your project files:
Before using Firebase Cloud Messaging, you must first have ensured you have initialized FlutterFire.
Messaging currently only supports usage with the default Firebase App instance.
FCM via APNs does not work on iOS Simulators. To receive messages & notifications a real device is required.
The Cloud Messaging package connects applications to the Firebase Cloud Messaging (FCM) service. You can send message payloads directly to devices at no cost. Each message payload can be up to 4 KB in size, containing pre-defined or custom data to suit your applications requirements.
Common use-cases for using messages could be:
- Displaying a notification (see Notifications).
- Syncing message data silently on the device (e.g. via shared_preferences).
- Updating the application's UI.
To learn about how to send messages to devices from your own server setup, view the Server Integration documentation.
Depending on a device's state, incoming messages are handled differently. To understand these scenarios & how to integrate FCM into your own application, it is first important to establish the various states a device can be in:
|Foreground||When the application is open, in view & in use.|
|Background||When the application is open, however in the background (minimised). This typically occurs when the user has pressed the "home" button on the device, has switched to another app via the app switcher or has the application open on a different tab (web).|
|Terminated||When the device is locked or the application is not running. The user can terminate an app by "swiping it away" via the app switcher UI on the device or closing a tab (web).|
There are a few preconditions which must be met before the application can receive message payloads via FCM:
- The application must have opened at least once (to allow for registration with FCM).
- On iOS, if the user swipes away the application from app Switcher, it must be manually reopened again for background messages to start working again.
- On Android, if the user force quits the app from device settings, it must be manually reopened again for messages to start working.
- On iOS & macOS, you must have correctly setup your project to integrate with FCM and APNs.
- On web, you must have requested a token (via
getToken) with the key of a "Web Push certificate".
On iOS, macOS & web, before FCM payloads can be received on your device, you must first ask the user's permission. Android applications are not required to request permission.
firebase_messaging package provides a simple API for requesting permission via the
This API accepts a number of named arguments which define the type of permissions you'd like to request, such as whether
messaging containing notification payloads can trigger a sound or read out messages via Siri. By default,
the method requests sensible default permissions. The reference API provides full documentation on what each permission is for.
To get started, call the method from your application (on iOS a native modal will be displayed, on web the browser's native API flow will be triggered):
NotificationSettings class returned from
the request details information regarding the user's decision.
authorizationStatus property can return a value which can be used to determine the user's overall decision:
authorized: The user granted permission.
denied: The user denied permission.
notDetermined: The user has not yet chosen whether to grant permission.
provisional: The user granted provisional permission (see Provisional Permission).
authorizedif the user has not disabled notifications for the app via the operating systems settings.
The other properties on
NotificationSettings return whether a specific permission is enabled, disabled or not supported on the current
For further information, view the Permissions documentation.
Once permission has been granted & the different types of device state have been understood, your application can now start to handle the incoming FCM payloads.
On the web, before a message can be sent to the browser you must do two things.
- Create an initial handshake with Firebase by passing in the public
messaging.getToken(vapidKey: 'KEY')method. Head over to the Firebase Console and create a new "Web Push Certificate". A key will be provided, which you can provide to the method:
- Create a
firebase-messaging-sw.jsfile inside the
web/directory in the root of your project. In your
web/index.htmlfile, please ensure this file is referenced and registered as a
serviceWorkeras demonstrated below:
A message payload can be viewed as one of three types:
- Notification only message: The payload contains a
notificationproperty, which will be used to present a visible notification to the user.
- Data only message: Also known as a "silent message", this payload contains custom key/value pairs within the
dataproperty which can be used how you see fit. These messages are considered "low priority" (more on this later).
- Notification & Data messages: Payloads with both
Based on your application's current state, incoming payloads require different implementations to handle them:
|Notification & Data|
Data only messages are considered low priority by devices when your application is in the background or terminated, and will be ignored. You can however explicitly increase the priority by sending additional properties on the FCM payload:
- On Android, set the
- On Apple (iOS & macOS), set the
Since the sending of FCM payloads is custom to your own setup, it is best to read the official FCM API reference for your chosen Firebase Admin SDK.
To listen to messages whilst your application is in the foreground, listen to the
The stream contains a
various information about the payload, such as where it was from, the unique ID, sent time, whether it contained
a notification & more. Since the message was retrieved whilst your application is in the foreground, you can directly access your Flutter
application's state & context.
Notification messages which arrive whilst the application is in the foreground will not display a visible notification by default, on both Android & iOS. It is, however, possible to override this behavior:
- On Android, you must create a "High Priority" notification channel.
- On iOS, you can update the presentation options for the application.
More details on this are discussed in the Notification: Foreground notifications documentation.
The process of handling background messages is currently different on Android/Apple & web based platforms. We're working to see if it's possible to align these flows.
Handling messages whilst your application is in the background is a little different. Messages can
be handled via the
onBackgroundMessage handler. When received, an
isolate is spawned (Android only, iOS/macOS does not require a separate isolate) allowing you to handle messages even when your application is not running.
There are a few things to keep in mind about your background message handler:
- It must not be an anonymous function.
- It must be a top-level function (e.g. not a class method which requires initialization).
Since the handler runs in its own isolate outside your applications context, it is not possible to update application state or execute any UI impacting logic. You can, however, perform logic such as HTTP requests, perform IO operations (e.g. updating local storage), communicate with other plugins etc.
It is also recommended to complete your logic as soon as possible. Running long, intensive tasks impacts device performance and may cause the OS to terminate the process. If tasks run for longer than 30 seconds, the device may automatically kill the process.
To get started, create a new file in the your
web directory, and call it
The file must import both the app and messaging SDKs, initialize Firebase and expose the
Next, the worker must be registered. Within the entry file, after the
main.dart.js file has loaded, register your worker:
Next restart your Flutter application. The worker will be registered and any background messages will be handled via this file.
If your message is a notification one (includes a
notification property), the Firebase SDKs will intercept this and display a visible
notification to your users (assuming you have requested permission & the user has notifications enabled). Once displayed, the
background handler will be executed (if provided).
To learn about how to handle user interaction with a notification, view the Notifications documentation.
FlutterFirebase Messaging does now support debugging and hot reloading for background isolates, but only if your main isolate is also being debugged, (e.g. run your application in debug and then background it by switching apps so it's no longer in the foreground).
For viewing additional logs on iOS, the "console.app" application on your Mac also displays system logs for your iOS device, including those from Flutter.
As mentioned above, data only messages are classed as "low priority". Devices can throttle and ignore these messages if your application is in the background, terminated, or a variety of other conditions such as low battery or currently high CPU usage.
You should not rely on data only messages to be delivered. They should only be used to support your application's non-critical functionality, e.g. pre-fetching data so the next time the user opens your app the data is ready to be displayed and if the message never gets delivered then your app still functions and fetches data on open.
To help improve delivery, you can bump the priority of messages. Note: this still does not guarantee delivery.
For example, if using the
firebase-admin NodeJS SDK package to send notifications via your server, add additional properties to the
This configuration provides the best chance that your data-only message will be delivered to the device. You can read full descriptions on the use of the properties on the official Firebase documentation.
Apple has very strict undisclosed polices on data only messages, which are very frequently ignored. For example, sending too many in a certain time period will cause the device to block messages, or if CPU consumption is high they will also be blocked.
For Android, you can view Logcat logs which will give a descriptive message on why a notification was not delivered. On Apple platforms the "console.app" application will display "CANCELED" logs for those it chose to ignore, however doesn't provide a description as to why.
Topics are a mechanism which allow a device to subscribe and unsubscribe from named PubSub channels, all managed via FCM. Rather than sending a message to a specific device by FCM token, you can instead send a message to a topic and any devices subscribed to that topic will receive the message.
Topics allow you to simplify FCM server integration as you do not need to keep a store of device tokens. There are, however, some things to keep in mind about topics:
- Messages sent to topics should not contain sensitive or private information. Do not create a topic for a specific user to subscribe to.
- Topic messaging supports unlimited subscriptions for each topic.
- One app instance can be subscribed to no more than 2000 topics.
- The frequency of new subscriptions is rate-limited per project. If you send too many subscription requests in a short period of time, FCM servers will respond with a 429 RESOURCE_EXHAUSTED ("quota exceeded") response. Retry with an exponential backoff.
- A server integration can send a single message to multiple topics at once. This, however, is limited to 5 topics.
To learn more about how to send messages to devices subscribed to topics, view the Send messages to topics documentation.
To subscribe a device, call the
subscribeToTopic method with the topic name:
To unsubscribe from a topic, call the
unsubscribeFromTopic method with the topic name: