Cloud Messaging
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.
To create a new Messaging instance, call the instance
getter on
FirebaseMessaging
:
Messaging currently only supports usage with the default Firebase App instance.
#
Receiving messagesiOS Simulators
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:
State | Description |
---|---|
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".
#
Requesting permission (Apple & Web)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.
The firebase_messaging
package provides a simple API for requesting permission via the requestPermission
method.
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):
The NotificationSettings
class returned from
the request details information regarding the user's decision.
The 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).
On Android
authorizationStatus
will returnauthorized
if 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
device.
For further information, view the Permissions documentation.
#
Handling messagesOnce permission has been granted & the different types of device state have been understood, your application can now start to handle the incoming FCM payloads.
#
Web TokensOn 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
vapidKey
tomessaging.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.js
file inside theweb/
directory in the root of your project. In yourweb/index.html
file, please ensure this file is referenced and registered as aserviceWorker
as demonstrated below:
For a complete
firebase_messaging
web demonstration, please run our example app found here. Take care to ensure you have setup theweb/firebase-messaging-sw.js
file found here.
#
Message typesA message payload can be viewed as one of three types:
- Notification only message: The payload contains a
notification
property, 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
data
property which can be used how you see fit. These messages are considered "low priority" (more on this later). - Notification & Data messages: Payloads with both
notification
anddata
properties.
Based on your application's current state, incoming payloads require different implementations to handle them:
Foreground | Background | Terminated | |
---|---|---|---|
Notification | onMessage | onBackgroundMessage | onBackgroundMessage |
Data | onMessage | onBackgroundMessage (see below) | onBackgroundMessage (see below) |
Notification & Data | onMessage | onBackgroundMessage | onBackgroundMessage |
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
priority
field tohigh
. - On Apple (iOS & macOS), set the
content-available
field totrue
.
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.
#
Foreground messagesTo listen to messages whilst your application is in the foreground, listen to the onMessage
stream.
The stream contains a RemoteMessage
, detailing
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.
#
Foreground & Notification messagesNotification 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.
#
Background messagesThe 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.
- Android/Apple
- Web
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.
Web requires you to register a JavaScript Service Worker which runs in the background.
Unfortunately we haven't yet been able to establish a proper way of communicating with the Service Worker and Flutter applications. Right now, all web background code must be executed in the JavaScript Service Worker file.
To get started, create a new file in the your web
directory, and call it firebase-messaging-sw.js
:
The file must import both the app and messaging SDKs, initialize Firebase and expose the messaging
variable.
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.
#
NotificationsIf 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.
#
Debugging & Hot ReloadFlutterFirebase 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.
#
Low priority messagesAs 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
message payload:
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.
#
TopicsTopics 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.
#
Subscribing to topicsTo subscribe a device, call the subscribeToTopic
method with the topic name:
#
Unsubscribing from topicsTo unsubscribe from a topic, call the unsubscribeFromTopic
method with the topic name: