# Firebase Messaging

> Use when setting up Firebase Cloud Messaging, managing permissions and tokens, handling background/foreground notification taps, or dispatching messages server-side (HTTP v1).

- **Type:** Skill
- **Install:** `agentstack add skill-evanca-flutter-ai-rules-firebase-messaging`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [evanca](https://agentstack.voostack.com/s/evanca)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [evanca](https://github.com/evanca)
- **Source:** https://github.com/evanca/flutter-ai-rules/tree/main/skills/firebase-messaging

## Install

```sh
agentstack add skill-evanca-flutter-ai-rules-firebase-messaging
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Firebase Cloud Messaging Skill

This skill defines how to correctly use Firebase Cloud Messaging (FCM) in Flutter applications.

## When to Use

Use this skill when:

* Setting up push notifications with FCM in a Flutter project.
* Handling messages in foreground, background, and terminated states.
* Managing notification permissions and FCM tokens.
* Configuring platform-specific notification display behavior.

---

## 1. Setup and Configuration

```
flutter pub add firebase_messaging
```

**iOS:**
- Enable **Push Notifications** and **Background Modes** in Xcode.
- Upload your **APNs authentication key** to Firebase before using FCM.
- Do **not** disable method swizzling — it is required for FCM token handling.
- Ensure the bundle ID for your APNs authentication key matches your app's bundle ID.

**Android:**
- Devices must run **Android 4.4+** with Google Play services installed.
- Check for Google Play services compatibility in both `onCreate()` and `onResume()`.

**Web:**
- Create and register a service worker file named `firebase-messaging-sw.js` in your `web/` directory:

```js
importScripts("https://www.gstatic.com/firebasejs/10.7.0/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/10.7.0/firebase-messaging-compat.js");

firebase.initializeApp({ /* your config */ });

const messaging = firebase.messaging();

messaging.onBackgroundMessage((message) => {
  console.log("onBackgroundMessage", message);
});
```

---

## 2. Message Handling

**Foreground messages:**

```dart
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  print('Foreground message data: ${message.data}');
  if (message.notification != null) {
    print('Notification: ${message.notification}');
  }
});
```

**Background messages:**

```dart
@pragma('vm:entry-point')
Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // Initialize Firebase before using other Firebase services in background
  await Firebase.initializeApp();
  print("Background message: ${message.messageId}");
}

void main() {
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(MyApp());
}
```

Background handler rules:
- Must be a **top-level function** (not anonymous, not a class method).
- Annotate with `@pragma('vm:entry-point')` (Flutter 3.3.0+) to prevent removal during tree shaking in release mode.
- Cannot update app state or execute UI-impacting logic — runs in a separate isolate.
- Call `Firebase.initializeApp()` before using any other Firebase services.

---

## 3. Permissions

```dart
NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
  alert: true,
  badge: true,
  sound: true,
  announcement: false,
  carPlay: false,
  criticalAlert: false,
  provisional: false,
);

print('Authorization status: ${settings.authorizationStatus}');
```

- **iOS / macOS / Web / Android 13+:** Must request permission before receiving FCM payloads.
- **Android ` block in `AndroidManifest.xml`:
  ```xml
  
  ```

---

## 6. Auto-Initialization Control

**Disable auto-init — iOS** (`Info.plist`):
```
FirebaseMessagingAutoInitEnabled = NO
```

**Disable auto-init — Android** (`AndroidManifest.xml`):
```xml

```

**Re-enable at runtime:**
```dart
await FirebaseMessaging.instance.setAutoInitEnabled(true);
```

- The auto-init setting **persists across app restarts** once set.

---

## 7. iOS Image Notifications

> **Important:** The iOS simulator does **not** display images in push notifications. Test on a physical device.

- Add a **Notification Service Extension** in Xcode.
- Use `Messaging.serviceExtension().populateNotificationContent()` in the extension for image handling.
- Swift: add the `FirebaseMessaging` Swift package to your extension target.
- Objective-C: add the `Firebase/Messaging` pod to your Podfile.

---

## 8. Notification Interaction Handling

When a user taps a notification, the app opens (or is brought to the foreground). Handle the interaction in both cases:

**App was terminated:**

```dart
RemoteMessage? initialMessage =
    await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
  // Navigate based on message content
}
```

**App was in background:**

```dart
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
  // Navigate based on message content
});
```

Always handle **both** scenarios to ensure a smooth user experience regardless of app state when the notification was received.

---

## 9. Topic Messaging

- Subscribing to a topic allows sending messages to multiple devices that have opted in.
- Topic messages are best suited for publicly available information (e.g., weather updates), optimized for throughput rather than latency.

```dart
// Subscribe
await FirebaseMessaging.instance.subscribeToTopic("weather_alerts");

// Unsubscribe
await FirebaseMessaging.instance.unsubscribeFromTopic("weather_alerts");
```

> **Note:** `subscribeToTopic()` and `unsubscribeFromTopic()` are not supported for web clients via the Flutter plugin.

---

## 10. Sending a Test Message

The official Firebase documentation often obscures the exact steps for sending a test push notification. To fire a push (test or real) using the Firebase Console:

1. Obtain your device's **FCM registration token** (see Section 4).
2. Go to the [Firebase Console](https://console.firebase.google.com/) and select your project.
3. In the left navigation panel, find the **Engage** (or **Run**) section and click **Messaging** (or **Cloud Messaging**).
4. Click **New campaign** and select **Notifications**.
5. Enter a **Notification title** and **Notification text**.
6. Click **Send test message** (often a button on the right side of the screen).
7. In the dialog, enter your **FCM registration token** and click the `+` icon to add it.
8. Make sure the token is checked, then click **Test**.

> To send real automated push notifications to production users, you must use a server implementation (via the FCM HTTP v1 API or the Firebase Admin SDK) rather than the console.

---

## 11. Server-Side Credentials & Security

The legacy FCM server key endpoint was deprecated in June 2024 — **HTTP v1 is the only supported option** for sending pushes.

To authenticate server-to-server calls for HTTP v1, you need a Service Account:
1. Go to **Firebase Console → Project settings → Service accounts**.
2. Click **Generate new private key** (downloads a `.json` file).
3. **CRITICAL:** This file contains highly sensitive secrets and **must never be committed to git**.
4. Store the file securely (e.g., in a Secret Manager) or pass its stringified contents as an environment variable (like `FIREBASE_SERVICE_ACCOUNT`) to your backend.

---

## 12. Sending Messages (HTTP v1)

To send an FCM HTTP v1 message, your backend must:
1. Complete an OAuth2 JWT exchange (sign with RS256, scope `https://www.googleapis.com/auth/firebase.messaging`, endpoint `https://oauth2.googleapis.com/token`).
2. Construct and `POST` a JSON payload to `https://fcm.googleapis.com/v1/projects/{project_id}/messages:send`.

Here is a minimal, complete working example using Node.js and the `google-auth-library`:

```javascript
const { GoogleAuth } = require('google-auth-library');

// Read the securely-stored service account JSON from environment
const credentials = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);

async function getAccessToken() {
  const auth = new GoogleAuth({
    credentials,
    scopes: ['https://www.googleapis.com/auth/firebase.messaging']
  });
  const client = await auth.getClient();
  const token = await client.getAccessToken();
  return token.token;
}

async function sendPushNotification(fcmToken, title, body) {
  const accessToken = await getAccessToken();
  const projectId = credentials.project_id;
  const url = `https://fcm.googleapis.com/v1/projects/${projectId}/messages:send`;
  
  const payload = {
    message: {
      token: fcmToken,
      notification: {
        title: title,
        body: body,
      },
      // Target specific platform features (e.g., channel on Android, sound on iOS)
      android: {
        notification: {
          channel_id: 'high_importance_channel',
        }
      },
      apns: {
        payload: {
          aps: {
            sound: 'default',
          }
        }
      }
    }
  };

  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
  });

  return response.json();
}
```

---

## References

- [Firebase Cloud Messaging Flutter documentation](https://firebase.google.com/docs/cloud-messaging/flutter/client)
- [Send a test message to a backgrounded app](https://firebase.google.com/docs/cloud-messaging/flutter/first-message)
- [Receive messages in Flutter](https://firebase.google.com/docs/cloud-messaging/flutter/receive)
- [Topic messaging on Flutter](https://firebase.google.com/docs/cloud-messaging/flutter/topic-messaging)
- [Migrate from legacy FCM APIs to HTTP v1](https://firebase.google.com/docs/cloud-messaging/migrate-v1)
- [Server environment authorization (for OAuth2 / Service Accounts)](https://firebase.google.com/docs/cloud-messaging/auth-server)
- [FCM HTTP v1 API Reference](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages)
- [Android Receive Docs (for default channel ID)](https://firebase.google.com/docs/cloud-messaging/android/receive)
- [FirebaseMessaging setForegroundNotificationPresentationOptions (API Reference)](https://pub.dev/documentation/firebase_messaging/latest/firebase_messaging/FirebaseMessaging/setForegroundNotificationPresentationOptions.html)

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [evanca](https://github.com/evanca)
- **Source:** [evanca/flutter-ai-rules](https://github.com/evanca/flutter-ai-rules)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-evanca-flutter-ai-rules-firebase-messaging
- Seller: https://agentstack.voostack.com/s/evanca
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
