Local notifications are a great way to engage users even when they are not actively using your Flutter app. They can be used to remind users of upcoming events, provide updates, or encourage them to return to your app. Implementing local notifications in Flutter involves using plugins and writing specific platform-dependent code.
What are Local Notifications?
Local notifications are messages that your app can display to users when the app is not in the foreground. Unlike push notifications, local notifications are scheduled and delivered by the app itself, without needing a server.
Why Use Local Notifications?
- User Engagement: Keep users informed and engaged with your app.
- Reminders: Remind users of tasks, events, or appointments.
- Offline Functionality: Notifications can be scheduled even without an internet connection.
How to Implement Local Notifications in Flutter
Implementing local notifications in Flutter involves using the flutter_local_notifications plugin.
Step 1: Add the flutter_local_notifications Dependency
Add the flutter_local_notifications package to your pubspec.yaml file:
dependencies:
flutter_local_notifications: ^16.3.0
Then, run flutter pub get to install the dependency.
Step 2: Initialize the Plugin
Initialize the plugin in your main.dart file. This includes setting up the necessary initialization settings for both Android and iOS.
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter/material.dart';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('app_icon'); // Replace 'app_icon' with the name of your app's icon file
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
const InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Local Notifications Example'),
),
body: NotificationScreen(),
),
);
}
}
Note: Ensure that the app_icon.png (or the name of your app icon) exists in the android/app/src/main/res/drawable directory for Android.
Step 3: Request Permissions (iOS)
For iOS, you need to request permissions to send notifications. You can do this when initializing the plugin.
// Already included in the initialization above
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
Step 4: Display a Simple Notification
Create a function to show a simple local notification. You can customize the title, body, and other parameters.
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class NotificationScreen extends StatelessWidget {
Future showNotification() async {
const AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
'your_channel_id', 'your_channel_name',
channelDescription: 'your_channel_description',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker');
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidNotificationDetails);
await flutterLocalNotificationsPlugin.show(
0, 'Test title', 'Test body', platformChannelSpecifics);
}
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: Text('Show Notification'),
onPressed: showNotification,
),
);
}
}
Step 5: Schedule a Notification
You can schedule a notification to be displayed at a specific time in the future.
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz;
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
class NotificationScreen extends StatefulWidget {
@override
_NotificationScreenState createState() => _NotificationScreenState();
}
class _NotificationScreenState extends State {
@override
void initState() {
super.initState();
_configureLocalTimeZone();
}
Future _configureLocalTimeZone() async {
tz.initializeTimeZones();
final String? timeZoneName = await FlutterNativeTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(timeZoneName!));
}
Future scheduleNotification() async {
await flutterLocalNotificationsPlugin.zonedSchedule(
0,
'Scheduled Title',
'Scheduled Body',
tz.TZDateTime.now(tz.local).add(const Duration(seconds: 5)),
const NotificationDetails(
android: AndroidNotificationDetails(
'your_channel_id', 'your_channel_name',
channelDescription: 'your_channel_description')),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
matchDateTimeComponents: DateTimeComponents.time);
}
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: Text('Schedule Notification'),
onPressed: scheduleNotification,
),
);
}
}
In this example:
- We initialize the timezone using the
timezoneandflutter_native_timezonepackages. - The
zonedSchedulemethod schedules a notification for 5 seconds in the future. - You also need to add the
timezoneandflutter_native_timezonedependencies to yourpubspec.yaml:
dependencies:
timezone: ^0.9.2
flutter_native_timezone: ^2.0.0
Step 6: Handle Notification Taps
To handle when a user taps on a notification, you need to set up a callback function.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('app_icon');
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
onDidReceiveLocalNotification:
(int id, String? title, String? body, String? payload) async {
// Handle notification tap on iOS
},
);
const InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse:
(NotificationResponse notificationResponse) async {
// Handle notification tap
print('Notification payload: ${notificationResponse.payload}');
},
);
runApp(MyApp());
}
You can set a payload when showing the notification to pass custom data to the callback function.
Platform-Specific Setup
Android
- Ensure you have an icon file (
app_icon.png) in theandroid/app/src/main/res/drawabledirectory. - Add the following meta-data to your
AndroidManifest.xmlfile within the<application>tag:
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/app_icon" />
iOS
- Request permissions for notifications.
- Ensure that background modes are enabled for remote notifications in the Xcode project settings (if needed).
Conclusion
Local notifications in Flutter can greatly enhance user engagement by providing timely reminders and updates. Using the flutter_local_notifications plugin, you can easily implement and customize notifications for both Android and iOS platforms. Remember to handle permissions, set up appropriate initialization, and manage notification taps to create a seamless user experience.