Skip to content
Development
Skill

/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).

From plugin
flutter-ai-skills
67036 skills

Claude Code

$ npx -y skills add evanca/flutter-ai-rules --skill firebase-messaging --agent claude-code

SKILL.md

firebase-messaging.SKILL.md
name: firebase-messaging
description: "Use when setting up Firebase Cloud Messaging, managing permissions and tokens, handling background/foreground notification taps, or dispatching messages server-side (HTTP v1)."
license: MIT

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:
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:**

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

**Background messages:**

@pragma('vm:entry-point')
Future<void> _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

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 < 13:** `authorizationStatus` returns `authorized` if the user has not disabled notifications in OS settings.
  • **Android 13+:** Track permission requests in your app — there's no way to determine if the user chose to grant/deny.
  • Use **provisional permissions** on iOS (`provisional: true`) to let users choose notification types after receiving their first notification.

---

4. Token Management

**Get FCM registration token (use to send messages to a specific device):**

final fcmToken = await FirebaseMessaging.instance.getToken();

**Web — provide VAPID key:**

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

**Listen for token refresh:**

FirebaseMessaging.instance.onTokenRefresh.listen((fcmToken) {
  // Send updated token to your application server
}).onError((err) {
  // Handle error
});

**Apple platforms — ensure APNS token is available before FCM calls:**

final apnsToken = await FirebaseMessaging.instance.getAPNSToken();
if (apnsToken != null) {
  // Safe to make FCM plugin API requests
}

**Token Lifecycle (Auth State):** Tokens should be tied to user sessions. Save the token to your database when a user signs in, and **delete** the token (or remove it from the user's document) when they sign out. An FCM token is device-specific, not inherently tied to user auth data — failing to clear it on sign-out means the next user on that device might receive the previous user's notifications.

---

5. Platform-Specific Behavior

  • **iOS:** If the user swipes away the app from the app switcher, it must be **manually reopened** for background messages to work again.
  • **Android:** If the user force-quits from device settings, the app must be **manually reopened**.
  • **iOS foreground notifications:** Update presentation options to display notifications while the app is in the foreground:
  await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
    alert: true,
    badge: true,
    sound: true,
  );
  • **Android foreground notifications:** Notification messages arriving while the app is in the foreground won't display a visible notification by default. You must consume the payload via the `onMessage` stream and manually display a visual cue (using your own UI logic or a local notifications plugin).
  • **Android default channel:** To set a default channel for background notifications, add this `meta-data` to your `<application>` block in `AndroidManifest.xml`:
  <meta-data
      android:name="com.google.firebase.messaging.default_notification_channel_id"
      android:value="high_importance_channel" />

---

6. Auto-Initialization Control

**Disable auto-init — iOS** (`

Read more
@evanca
Ships withflutter-ai-skills

36 Flutter and Dart skills your coding agent loads by itself, sourced only from official documentation. A skill is a folder with a SKILL.md file.

Stars on GitHub

Momentum

stars in total
670
Star history of evanca/flutter-ai-rules on GitHub, a chart by star-history.com

Other skills on flutter-ai-skills.

accessibility

accessibility

Use when working on accessibility, a11y, WCAG, ARIA, screen readers, keyboard nav, focus order, contrast, alt text, captions,…

bloc

bloc

Use when creating a Cubit or Bloc, modeling state with sealed classes or status enums, wiring…

dart-3-updates

dart-3-updates

Use when writing switch statements, refactoring if-else chains, creating data classes, choosing records vs classes, destructuring…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about firebase-messaging.

Which coding agents can use firebase-messaging?
firebase-messaging installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.