Android Notification Channels
Android Notification Channels
Starting with Android 8.0 (API level 26 / Oreo), all notifications must be assigned to a notification channel. A channel is a named grouping that lets users control notification behavior — such as importance level, sound, lights, and vibration — independently for each category of notification your app produces. Without a channel, notifications are silently dropped on Android 8+.
In Flutter, you configure notification channels through the flutter_local_notifications package and through the AndroidManifest.xml for FCM (Firebase Cloud Messaging). Understanding how to create, configure, and assign channels correctly is essential for any production Flutter app that targets Android.
Why Channels Matter
Before Android Oreo, apps controlled notification behavior globally. Now, users control behavior per channel from Settings. Once a channel is created, your app cannot change its importance or sound — only the user can. This means you must design your channels thoughtfully from the start:
- Group related notifications (e.g., "Messages", "Promotions", "System Alerts")
- Set the correct importance level so the channel behaves appropriately by default
- Choose sound and vibration settings that match the notification's urgency
- Give each channel a clear, user-facing name and description
Importance Levels
The Importance enum (in flutter_local_notifications) maps directly to Android's NotificationManager importance constants:
- max / high — Makes a sound, pops up on screen (heads-up notification). Use for urgent alerts like incoming calls or alarms.
- defaultImportance — Makes a sound, shown in the status bar. Suitable for messages and reminders.
- low — No sound, no visual interruption; appears silently in the notification shade.
- min — No sound, no icon in the status bar; only visible when the shade is pulled down.
- none — Channel effectively disabled; notifications are not shown.
Creating a Channel with flutter_local_notifications
The most complete way to define a channel in Flutter is at plugin initialization. You pass an AndroidNotificationChannel object and call createNotificationChannel before showing any notifications.
Defining and Registering Channels at App Startup
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
/// Call this once from main() before runApp().
Future<void> initNotifications() async {
// 1. Define each channel
const AndroidNotificationChannel messagesChannel = AndroidNotificationChannel(
'messages_channel', // channel id (unique per app)
'Messages', // user-visible name
description: 'Notifications for new chat messages.',
importance: Importance.high, // heads-up + sound
playSound: true,
enableVibration: true,
enableLights: true,
ledColor: Color(0xFF00BCD4), // teal LED
);
const AndroidNotificationChannel promoChannel = AndroidNotificationChannel(
'promotions_channel',
'Promotions',
description: 'Deals, offers, and promotional content.',
importance: Importance.low, // silent, no heads-up
playSound: false,
enableVibration: false,
);
// 2. Register each channel with the OS
final androidPlugin =
flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
await androidPlugin?.createNotificationChannel(messagesChannel);
await androidPlugin?.createNotificationChannel(promoChannel);
// 3. Initialise the plugin itself
const AndroidInitializationSettings androidSettings =
AndroidInitializationSettings('@mipmap/ic_launcher');
await flutterLocalNotificationsPlugin.initialize(
const InitializationSettings(android: androidSettings),
);
}
createNotificationChannel on an already-existing channel is safe — Android simply updates any mutable properties (like description) and ignores attempts to change importance or sound if the channel already exists. This means you can safely call it on every app launch.Assigning a Channel When Showing a Local Notification
Every time you show a notification, you must specify the channelId in your AndroidNotificationDetails. The channel must have been created beforehand.
Showing a Notification on a Specific Channel
Future<void> showMessageNotification({
required int id,
required String senderName,
required String messageText,
}) async {
const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
'messages_channel', // must match the channel id you registered
'Messages', // channel name (shown in settings)
channelDescription: 'Notifications for new chat messages.',
importance: Importance.high,
priority: Priority.high,
ticker: 'New message',
styleInformation: BigTextStyleInformation(''),
);
await flutterLocalNotificationsPlugin.show(
id,
senderName,
messageText,
const NotificationDetails(android: androidDetails),
);
}
Future<void> showPromoNotification({
required int id,
required String title,
required String body,
}) async {
const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
'promotions_channel',
'Promotions',
channelDescription: 'Deals, offers, and promotional content.',
importance: Importance.low,
priority: Priority.low,
);
await flutterLocalNotificationsPlugin.show(
id,
title,
body,
const NotificationDetails(android: androidDetails),
);
}
Assigning FCM Notifications to a Channel
For Firebase Cloud Messaging (FCM) push notifications, the channel assignment happens in two places:
- AndroidManifest.xml — sets the default channel for all FCM messages that do not specify one
- FCM payload — the
android.notification.channel_idfield in the server-sent message overrides the default for that specific notification
Add the default channel to your AndroidManifest.xml inside the <application> tag:
AndroidManifest.xml — Default FCM Channel
<!-- Place inside <application> in android/app/src/main/AndroidManifest.xml -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="messages_channel" />
Custom Sound and Vibration Patterns
Channels support custom sounds (a raw audio resource) and custom vibration patterns (a Int64List of millisecond durations alternating off/on):
- Place the sound file (e.g.,
notification_sound.mp3) inandroid/app/src/main/res/raw/ - Reference it with a
RawResourceAndroidNotificationSoundobject - Vibration patterns follow the format: delay, on, off, on, off …
Deleting a Channel
If you rename or retire a channel, delete the old one to keep the user's notification settings clean. Use deleteNotificationChannel(channelId). Note that once deleted, a new channel with the same ID starts fresh — the user's previous customisations are lost.
Summary
Android notification channels are a mandatory layer of control introduced in Android 8.0. In Flutter you define channels with AndroidNotificationChannel, register them via createNotificationChannel, and reference the correct channelId in every AndroidNotificationDetails you create. For FCM, declare the default channel in AndroidManifest.xml and optionally override it per message in the server payload. Design your channel taxonomy thoughtfully — importance and sound settings become user-controlled the moment a channel is created.