Introduction
Flutter local notifications are vital for engaging users with timely reminders, alerts, or updates—even when the app runs in the background. The flutter_local_notifications plugin offers a unified way to schedule and display notifications on Android, iOS, and macOS. In this intermediate guide, you’ll learn how to set up flutter_local_notifications, configure channels, trigger immediate and scheduled notifications, customize appearance, and handle user interaction.
Plugin Setup and Initialization
Begin by adding the plugin to your pubspec.yaml:
dependencies:
flutter_local_notifications
Run flutter pub get. Next, initialize the plugin in your main.dart:
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
final iosSettings = DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
final initSettings = InitializationSettings(android: androidSettings, iOS: iosSettings);
await flutterLocalNotificationsPlugin.initialize(
initSettings,
onDidReceiveNotificationResponse: (response) {
},
);
runApp(MyApp());
}Key steps:
• Android: define a notification channel (required for API ≥26).
• iOS: request permissions for alert, sound, badge.
• Provide an onDidReceiveNotificationResponse callback to catch taps.
Immediate and Scheduled Notifications
To trigger an immediate notification:
Future<void> showImmediateNotification() async {
const androidDetails = AndroidNotificationDetails(
'default_channel', 'Default', channelDescription: 'General notifications',
importance: Importance.max, priority: Priority.high,
);
const iosDetails = DarwinNotificationDetails();
const notificationDetails = NotificationDetails(android: androidDetails, iOS: iosDetails);
await flutterLocalNotificationsPlugin.show(
0, 'Hello!', 'This is an immediate notification.', notificationDetails,
payload: 'immediate_payload',
);
}Scheduling a local notification in the future:
Future<void> scheduleNotification() async {
final scheduledTime = DateTime.now().add(Duration(hours: 2));
await flutterLocalNotificationsPlugin.zonedSchedule(
1,
'Reminder',
'Don’t forget to check your tasks.',
tz.TZDateTime.from(scheduledTime, tz.local),
const NotificationDetails(
android: AndroidNotificationDetails('reminder_channel', 'Reminders'),
iOS: DarwinNotificationDetails(),
),
androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
payload: 'scheduled_payload',
);
}Note: Initialize the timezone package (timezone and flutter_native_timezone) to use zonedSchedule.
Customization and Interaction
The plugin supports rich customization:
• Large icons, custom sounds, vibration patterns.
• Action buttons (Android) to handle inline user responses.
• Grouped notifications for bundling.
Example of adding a custom sound and large icon:
final androidDetails = AndroidNotificationDetails(
'custom_channel', 'Custom',
icon: 'app_icon',
largeIcon: const DrawableResourceAndroidBitmap('large_icon'),
sound: RawResourceAndroidNotificationSound('notification_sound'),
importance: Importance.high, priority: Priority.high,
);Handling taps: In your initialize callback, parse response.payload to navigate or perform logic. For example, route the user to a specific screen:
onDidReceiveNotificationResponse: (response) {
final payload = response.payload;
if (payload == 'scheduled_payload') {
navigatorKey.currentState?.pushNamed('/tasks');
}
}Advanced Scheduling and Repeats
For recurring notifications, use periodicallyShow:
await flutterLocalNotificationsPlugin.periodicallyShow(
2,
'Stand Up',
'Time to stretch your legs.',
RepeatInterval.hourly,
notificationDetails,
androidAllowWhileIdle: true,
);
For sophisticated scheduling (e.g., weekdays at 8 AM), compute the next instance with timezone-aware logic:
tz.TZDateTime nextInstance(int hour, int minute, Day day) {
final now = tz.TZDateTime.now(tz.local);
var scheduled = tz.TZDateTime(tz.local, now.year, now.month, now.day, hour, minute);
while (scheduled.weekday != day) {
scheduled = scheduled.add(Duration(days: 1));
}
if (scheduled.isBefore(now)) scheduled = scheduled.add(Duration(days: 7));
return scheduled;
}Then feed that into zonedSchedule with matchDateTimeComponents: DateTimeComponents.dayOfWeekAndTime to repeat weekly.
Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.
Conclusion
Integrating local notifications in Flutter improves user engagement by delivering timely alerts even when the app isn’t active. As you build your Flutter apps, leveraging robust local notification features will enhance usability and retention.