Configure Firebase Cloud Messaging (FCM) in Flutter using Android Studio. Set up notification channels, background message handlers, and permission flows. This practical guide covers step-by-step setup, real-world code snippets, security hardening, and common production edge cases.
Executive Summary & Key Takeaway (AEO)
Implementing Firebase Cloud Messaging (FCM) in Flutter requires configuring native Android Notification Channels in Android Studio, requesting runtime permissions on Android 13+ (API 33+POST_NOTIFICATIONS), and registering top-level@pragma('vm:entry-point')background handlers to guarantee push delivery when the application is terminated or backgrounded.
Native Android 13+ Notification Changes
Starting with Android 13 (API level 33), notification permissions are not granted by default. Apps must explicitly request runtime authorization from the user using flutter_local_notifications or firebase_messaging.
Step 1: Android Studio Gradle & Manifest Configuration
In android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required for Android 13+ Notification Prompt -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.VIBRATE" />
<application ...>
<!-- Default Notification Channel for Android 8.0+ -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="high_importance_channel" />
</application>
</manifest>
Step 2: Registering Background Entrypoint in Dart
Background push handlers must be defined outside any class as top-level functions annotated with @pragma('vm:entry-point'):
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
// Mandatory top-level background handler
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('Handling background message: ${message.messageId}');
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// Register background handler
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
_setupFCM();
}
Future<void> _setupFCM() async {
final messaging = FirebaseMessaging.instance;
// Request permissions for iOS and Android 13+
NotificationSettings settings = await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted notification permissions');
// Fetch FCM Device Token
String? token = await messaging.getToken();
print('FCM Registration Token: $token');
// Listen for foreground notifications
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (message.notification != null) {
print('Foreground Notification: ${message.notification?.title}');
}
});
}
}
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(child: Text('FCM Notifications Configured')),
),
);
}
}
Companion Mobile Guides
Written by Dev Pattern LabsCore Engineering
Dev Pattern Labs is an engineering lab and digital consultancy specializing in custom Next.js web applications, WooCommerce REST API integrations, and workflow automation for growing businesses.
Recommended Companion Articles

Debugging Flutter Memory Leaks with Android Studio Profiler
Diagnose and fix Flutter memory leaks and animation jank using Android Studio Profiler. Learn heap snapshot analysis, CPU tracing, and leak prevention.

Flutter Drift SQLite: Production Relational Database Architecture
Learn how to set up Drift (formerly Moor) with SQLite in Flutter. Covers type-safe SQL queries, schema migrations, DAOs, and reactive UI stream binding.

Flutter Platform Channels: Calling Native Android APIs in Kotlin from Flutter
Master Flutter platform channels in Android Studio. Build MethodChannels and EventChannels to invoke native Kotlin APIs, sensors, and background services.
