|---|---|
| **Select platform:** | [iOS+](https://firebase.google.com/docs/cloud-messaging/ios/get-started.md.txt) [Android](https://firebase.google.com/docs/cloud-messaging/android/get-started.md.txt) [Web](https://firebase.google.com/docs/cloud-messaging/web/get-started.md.txt) [Flutter](https://firebase.google.com/docs/cloud-messaging/flutter/get-started.md.txt) [Unity](https://firebase.google.com/docs/cloud-messaging/unity/get-started.md.txt) [C++](https://firebase.google.com/docs/cloud-messaging/cpp/get-started.md.txt) |

<br />

This guide describes how to get started with Firebase Cloud Messaging in your
Flutter client apps so that you can reliably send messages.

Depending on the platform you're targeting, there are some additional required
setup steps that you'll need to take.

## iOS+

<br />

### Enable app capabilities in XCode

<br />

Before your application can start to receive messages, you must enable push
notifications and background modes in your Xcode project.

1. Open your Xcode project workspace (\`ios/Runner.xcworkspace\`).
2. [Enable push
   notifications](https://help.apple.com/xcode/mac/current/#/devdfd3d04a1).
3. Enable the **Background fetch** and the **Remote notifications** [background
   execution modes](https://developer.apple.com/documentation/xcode/configuring-background-execution-modes).

<br />

<br />

<br />

### Upload your APNs
authentication key

<br />


Before you use FCM, upload your APNs authentication key to Firebase.
If you don't already have an APNs authentication key, create one in the
[Apple Developer Member Center](https://developer.apple.com/membercenter/index.action).

1. In the Firebase console, go to **Settings** \> **General** . Then, click the [**Cloud Messaging** tab](https://console.firebase.google.com/project/_/settings/cloudmessaging).
2. In **APNs authentication key** under **iOS app configuration** , click **Upload** to upload your development authentication key, or production authentication key, or both. At least one is required.
3. For each authentication key, select the `.p8` file, and provide the key ID and your Apple team ID. Click **Save**.

<br />

<br />

#### Method swizzling

To use the FCM Flutter plugin on Apple devices, method swizzling is
required. Without it, key Firebase features such as FCM registration
handling won't function properly.

## Android

### Google Play services

FCM clients require devices running Android 7.0 or
higher that also have Google Play services installed, or an emulator running
Android 7.0 with Google APIs. Note that you are not limited
to deploying your Android apps through Google Play Store.

Apps that rely on the Play Services SDK should always check the device for a
compatible Google Play services APK before accessing Google Play services
features. It is recommended to do this in two places: in the main activity's
`onCreate()` method, and in its `onResume()` method. The check in `onCreate()`
makes sure that the app can't be used without a successful check. The check in
`onResume()` makes sure that if the user returns to the running app through some
other means, such as through the back button, the check is still performed.

If the device doesn't have a compatible version of Google Play services, your
app can call
[`GoogleApiAvailability.makeGooglePlayServicesAvailable()`](https://developers.google.com/android/reference/com/google/android/gms/common/GoogleApiAvailability.html#public-methods)
to allow users to download Google Play services from the Play Store.

## Web

### Configure Web Credentials with FCM

The FCM Web interface uses Web credentials called Voluntary
Application Server Identification, or "VAPID" keys, to authorize send requests
to supported web push services. To subscribe your app to push notifications, you
need to associate a pair of keys with your Firebase project. You can either
generate a new key pair or import your existing key pair through the
Firebase console.

<br />

### Generate a new key pair

<br />

1. In the Firebase console, go to
   **Settings** \>
   **General** . Then, click the
   [**Cloud Messaging** tab](https://console.firebase.google.com/project/_/settings/cloudmessaging).

2. Go to the **Web configuration** section.

3. In the **Web Push certificates** tab, click **Generate Key Pair**.

   The console displays a notice that the key pair was generated, and it
   displays the public key string and date added.

<br />

<br />

<br />

### Import an existing key pair

<br />

If you have an existing key pair you are already using with your web app, you
can import it to FCM so that you can reach your existing web app
instances through FCM APIs. To import keys, you must have
owner-level access to the Firebase project. Import your existing public and
private key in base64 URL safe encoded form:

1. In the Firebase console, go to
   **Settings** \>
   **General** . Then, click the
   [**Cloud Messaging** tab](https://console.firebase.google.com/project/_/settings/cloudmessaging).

2. Go to the **Web configuration** section.

3. In the **Web Push certificates** tab, select
   **import an existing key pair**.

4. In the **Import a key pair** dialog, provide your public and private keys in
   the corresponding fields and click **Import**.

   The console displays the public key string and date added.

For more information about the format of the keys and how to generate them, see
[Application server keys](https://developers.google.com/web/fundamentals/push-notifications/web-push-protocol#application_server_keys).

<br />

<br />

## Install the FCM plugin

1. [Install and initialize the Firebase plugins for Flutter](https://firebase.google.com/docs/flutter/setup.md.txt)
   if you haven't already done so.

2. From the root of your Flutter project, run the following command to install
   the plugin:

   ```bash
   flutter pub add firebase_messaging
   ```
3. Once complete, rebuild your Flutter application:

   ```bash
   flutter run
   ```

## Request notification permission

To send a notification message to a device, you need to register the device with
FCM using `register()`. If notification permission has
not been granted, this method will ask the user for notification permissions.
Otherwise, it delivers the FID through `onRegistered` on success or rejects the
future due to an error.

> [!WARNING]
> **Warning:** In iOS SDK 10.4.0 and higher, it is required that the APNs token is available before making API requests. The APNs token is not guaranteed to have been received before making FCM plugin API requests.

```dart
// You may set the permission requests to "provisional" which allows the user to choose what type
// of notifications they would like to receive once the user receives a notification.
final notificationSettings = await FirebaseMessaging.instance.requestPermission(provisional: true);

// For apple platforms, make sure the APNS token is available before making any FCM plugin API calls
final apnsToken = await FirebaseMessaging.instance.getAPNSToken();
if (apnsToken != null) {
 // APNS token is available, make FCM plugin API requests...
}
```

## Access the Firebase Installation ID

> [!CAUTION]
> **Caution:** Don't use both the Firebase Installation ID APIs and the deprecated [registration token APIs](https://firebase.google.com/docs/cloud-messaging/flutter/get-started.md.txt#access-registration-token) for registration management at the same time. We recommend using Firebase Installation IDs (FIDs) to segment or target your app instances.

> [!TIP]
> **Tip:** See [Best practices for FCM registration
> management](https://firebase.google.com/docs/cloud-messaging/manage-tokens) for tips on managing registrations.

### Enable registration using Firebase Installation ID

To enable registering your app instance with FCM using the [Firebase
Installation ID (FID)](https://firebase.google.com/docs/projects/manage-installations), you must first
enable FIDs in your app's configuration for Android and Apple platforms (no
static opt-in configuration is required on Web):

#### Android

Add the following `<meta-data>` element inside the `<application>` element of your `AndroidManifest.xml`:

```
<meta-data android:name="firebase_messaging_installation_id_enabled"
           android:value="true" />
```

#### iOS+

Add the `FirebaseMessagingInstallationIdEnabled` key to your `Info.plist` and set it to `true` (`YES`):

```
<key>FirebaseMessagingInstallationIdEnabled</key>
<true/>
```

### Subscribe to the `onRegistered` stream

To send a message to your app instance on a specific device, you need the
[Firebase Installation ID (FID)](https://firebase.google.com/docs/projects/manage-installations.md.txt) of that
app instance once it has been registered with FCM. The FID is
delivered asynchronously through the `onRegistered` stream.

On Android and Apple platforms, FCM automatically registers the app
instance at startup when auto-initialization is enabled (the default). However,
an explicit call to `register()` is required:

- On **Web** . You can optionally pass `vapidKey` and `serviceWorkerScriptPath`.
- On **Android and Apple platforms** if [auto-initialization is
  disabled](https://firebase.google.com/docs/cloud-messaging/flutter/get-started#prevent-auto-init) or after calling `unregister()`. You can also call `register()` at any time to trigger `onRegistered` with the already registered FID.

Always subscribe to `onRegistered` before calling `register()` so that your
listener is active when the registration event is emitted:

```dart
final messaging = FirebaseMessaging.instance;

messaging.onRegistered
    .listen((String installationId) {
      // TODO: Send the Firebase Installation ID (FID) to your application server.
    })
    .onError((err) {
      // Error getting Firebase Installation ID.
    });

// Required on Web, and on Android/Apple if auto-initialization is disabled.
await messaging.register(
  // Optional on Web (ignored on Android and Apple platforms)
  vapidKey: "BKagOny0KF_2pCJQ3m....moL0ewzQ8rZu",
);
```

The `onRegistered` stream emits the FID in the following scenarios:

1. Automatically on initial app startup and routine sync on Android and Apple platforms when auto-initialization is enabled.
2. Every time a manual `register()` call finishes (even if the app instance is already registered, `onRegistered` still emits the already registered FID).
3. Whenever a Firebase Installation ID change is detected and the app is re-registered with FCM, or on Web when a [`pushsubscriptionchange`](https://www.w3.org/TR/push-api/#the-pushsubscriptionchange-event) event is fired.

After you've obtained the Firebase Installation ID (FID), send it to your app
server and store it using your preferred method.

## Access the registration token (deprecated)

> [!CAUTION]
> **Caution:** This feature is deprecated. Use [Firebase Installation
> IDs](https://firebase.google.com/docs/cloud-messaging/flutter/get-started#access-firebase-installation-id), as this method will be removed in a future release.

> [!TIP]
> **Tip:** See [Best practices for FCM registration
> management](https://firebase.google.com/docs/cloud-messaging/manage-tokens) for tips on managing registrations.

To send a message to a specific device, you need to know the device
registration token. To retrieve the registration token for an app instance, call
`getToken()`. If notification permission has not been granted, this method will
ask the user for notification permissions. Otherwise, it returns a token or
rejects the future due to an error.

On web platforms, pass your VAPID public key to `getToken()`:

```dart
final fcmToken = await FirebaseMessaging.instance.getToken(vapidKey: "BKagOny0KF_2pCJQ3m....moL0ewzQ8rZu");
```

To be notified whenever the token is updated, subscribe to the `onTokenRefresh`
stream:

```dart
FirebaseMessaging.instance.onTokenRefresh
    .listen((fcmToken) {
      // TODO: If necessary send token to application server.

      // Note: This callback is fired at each app startup and whenever a new
      // token is generated.
    })
    .onError((err) {
      // Error getting token.
    });
```

## Prevent auto initialization

When a FCM registration is generated, the library uploads
the identifier and configuration data to Firebase. If you prefer to prevent
auto registration, disable auto-initialization at build time.

When auto-initialization is disabled, you can explicitly register the app
instance at runtime by calling `register()` (make sure to subscribe to
`onRegistered` first to receive the Firebase Installation ID):

```dart
await FirebaseMessaging.instance.register();
```

### iOS

On iOS, add a metadata value to your `Info.plist`:

    FirebaseMessagingAutoInitEnabled = NO

### Android

On Android, disable Analytics collection and FCM auto initialization (you must
disable both) by adding these metadata values to your `AndroidManifest.xml`:

```xml
<meta-data
    android:name="firebase_messaging_auto_init_enabled"
    android:value="false" />
<meta-data
    android:name="firebase_analytics_collection_enabled"
    android:value="false" />
```

### Re-enable FCM auto-init at runtime

To enable auto-init for a specific app instance, call `setAutoInitEnabled()`:

```dart
await FirebaseMessaging.instance.setAutoInitEnabled(true);
```

This value persists across app restarts once set.

## Send a test notification message

1. Install and run the app on the target device. On Apple devices, you'll need
   to accept the request for permission to receive remote notifications.

2. Make sure the app is in the background on the device.

3. In the Firebase console, go to
   **DevOps \& Engagement** \>
   [**Messaging**](https://console.firebase.google.com/project/_/messaging/).

4. Create a campaign.

   - If this is your first message:

     1. Select **Create your first campaign**.

     2. Select **Firebase Notification messages** and select **Create**.

   - If you have previously created campaigns:

     1. On the **Campaigns** tab, select **New campaign**.

     2. Click **Notifications**.

5. Enter the message text.

6. Select **Send test message** from the right pane.

7. In the field labeled **Add a Firebase Installation ID or FCM
   registration token**, enter your registered Firebase Installation ID or
   registration token.

8. Select **Test**.

After you select **Test**, the targeted client device, with the app in the
background, should receive the notification.

For insight into message delivery to your app, go to the
**DevOps \& Engagement** \> **Messaging** \>
[**Reports** dashboard](https://console.firebase.google.com/project/_/notification/reporting)
in the Firebase console. This dashboard records the number of messages sent
and opened on Apple and Android devices, along with data for "impressions"
(notifications seen by users) for Android apps.

## Handling interaction

When users tap a notification, the default behavior on both Android and iOS is
to open the application. If the application is terminated, it will be started,
and if it is in the background, it will be brought to the foreground.

Depending on the content of a notification, you may want to handle the user's
interaction when the application opens. For example, if a new chat message is
sent using a notification and the user selects it, you may want to open the
specific conversation when the application opens.

The `firebase-messaging` package provides two ways to handle this interaction:

1. `getInitialMessage():` If the application is opened from a terminated state, this method returns a `Future` containing a `RemoteMessage`. Once consumed, the `RemoteMessage` will be removed.
2. `onMessageOpenedApp`: A`Stream` which posts a `RemoteMessage` when the application is opened from a background state.

To make sure your users have a smooth experience, you should handle both
scenarios. The following code example outlines how this can be achieved:

```
class Application extends StatefulWidget {
  @override
  State createState() => _Application();
}

class _Application extends State {
  // In this example, suppose that all messages contain a data field with the key 'type'.
  Future setupInteractedMessage() async {
    // Get any messages which caused the application to open from
    // a terminated state.
    RemoteMessage? initialMessage =
        await FirebaseMessaging.instance.getInitialMessage();

    // If the message also contains a data property with a "type" of "chat",
    // navigate to a chat screen
    if (initialMessage != null) {
      _handleMessage(initialMessage);
    }

    // Also handle any interaction when the app is in the background using a
    // Stream listener
    FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
  }

  void _handleMessage(RemoteMessage message) {
    if (message.data['type'] == 'chat') {
      Navigator.pushNamed(context, '/chat',
        arguments: ChatArguments(message),
      );
    }
  }

  @override
  void initState() {
    super.initState();

    // Run code required to handle interacted messages in an async function
    // as initState() must not be async
    setupInteractedMessage();
  }

  @override
  Widget build(BuildContext context) {
    return Text("...");
  }
}
```

How you handle interaction depends on your setup. The previously shown example
is a basic example of using a `StatefulWidget`.

## Next steps

After you have completed the setup steps, here are a few options for moving
forward with FCM for Flutter:

- [Send messages to devices](https://firebase.google.com/docs/cloud-messaging/server-environment.md.txt)
- [Receive messages in a Flutter app](https://firebase.google.com/docs/cloud-messaging/receive-messages.md.txt?platform=flutter)
- [Send messages to topics](https://firebase.google.com/docs/cloud-messaging/topic-messaging.md.txt)