I’m using the Flutter local notification package in my expiry reminder app. However, notifications about product expirations are inconsistent. Sometimes the notifications are delivered as expected, but most of the time, users do not receive them.
I want the functionality to be like alarm apps: when a user sets an expiration time for a product, they should reliably receive a notification at that time.
My main file code
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await MyDatabase().copyPasteAssetFileToRoot();
await MyDatabase().updateDayLeftForAllProducts();
// await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await NotificationHelper.init();
tz.initializeTimeZones();
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
// TODO: implement initState
super.initState();
_requestNotificationPermission();
}
Future<void> _requestNotificationPermission() async {
var status = await Permission.notification.status;
if (status.isDenied || status.isPermanentlyDenied) {
status = await Permission.notification.request();
if (status.isGranted) {
print("Notification permission granted.");
} else {
print("Notification permission denied.");
}
}
}
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AddItemsProvider()),
ChangeNotifierProvider(create: (_) => CategoryProvider()),
],
child: Sizer(builder: (context, orientation, screenType) {
return MaterialApp(
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
title: "Expiry Reminder",
home: SplashPage(),
);
}));
}
}
These is my Notification file code which is not working proper according to the requirement
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/timezone.dart' as tz;
class NotificationHelper {
static final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
static Future<void> onDidReceiveBackgroundNotification(
NotificationResponse notificationResponse) async {}
static Future<void> init() async {
const AndroidInitializationSettings androidInitializationSettings =
AndroidInitializationSettings('@drawable/launcher_icon');
const DarwinInitializationSettings iOSInitializationSettings =
DarwinInitializationSettings();
const InitializationSettings initializationSettings =
InitializationSettings(
android: androidInitializationSettings,
iOS: iOSInitializationSettings);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveBackgroundNotificationResponse:
onDidReceiveBackgroundNotification,
onDidReceiveNotificationResponse: onDidReceiveBackgroundNotification,
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestExactAlarmsPermission();
}
static Future<void> scheduleReminderNotifications({
required String productName,
required DateTime reminderDate,
required String reminderTime,
required String operation,
required int id,
}) async {
List<String> timeParts = reminderTime.split(":");
final scheduledDate = DateTime(
reminderDate.year,
reminderDate.month,
reminderDate.day,
int.parse(timeParts[0]),
int.parse(timeParts[1]),
);
if (scheduledDate.isBefore(DateTime.now())) {
print("Scheduled date must be in the future.");
return;
}
print("Scheduling notification for: $reminderDate for id: $id");
if (operation == "update") {
print("Cancel existing notification for id $id");
await cancelNotification(id);
}
await _scheduleNotification(
id: id,
title:
'Attention: ${productName[0].toUpperCase() + productName.substring(1)} Expiration Alert',
body:
'Heads up! Your $productName will expire on ${scheduledDate.toString().split(" ")[0]}.',
scheduledDate: scheduledDate,
);
}
static Future<void> cancelNotification(int id) async {
await flutterLocalNotificationsPlugin.cancel(id);
}
static Future<void> _scheduleNotification({
required int id,
required String title,
required String body,
required DateTime scheduledDate,
}) async {
const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: AndroidNotificationDetails(
"channelId",
"channelName",
importance: Importance.high,
priority: Priority.high,
),
iOS: DarwinNotificationDetails(),
);
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
body,
tz.TZDateTime.from(scheduledDate, tz.local),
platformChannelSpecifics,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
matchDateTimeComponents: DateTimeComponents.dateAndTime,
);
}
}
these is how i am adding the notifications
if (buttonText == "Add") {
if (reminderDate.text.isNotEmpty) {
NotificationHelper
.scheduleReminderNotifications(
productName: productName.text,
reminderDate: DateTime.parse(
reminderDate.text),
reminderTime:
reminderTimeValue.text,
operation: buttonText,
id: index,
);
}
//for update purpose
if (reminderDate.text.isNotEmpty) {
NotificationHelper
.scheduleReminderNotifications(
productName: productName.text,
reminderDate: DateTime.parse(
reminderDate.text),
reminderTime:
reminderTimeValue.text,
operation: "update",
id: index,
);
}
Please Solve the issue related to the notifications
Krishiraj Vansia is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
All implementations is correct, for showing zonedSchedule
notifications, timezones have to be initialized to latest timezone.
Try initializing tz.initializeTimeZones()
in NotificationHelper
class instead of main.dart
,
import 'package:timezone/data/latest.dart' as tz;
tz.initializeTimeZones();
And replace import of tzone
as:
import 'package:timezone/timezone.dart' as tzone;
replace date parameters as tzone.TZDateTime timeToset =
tzone.TZDateTime.from(scheduledDate, tzone.local);
import'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/timezone.dart' as tzone;
import 'package:timezone/data/latest.dart' as tz;
class NotificationHelper {
static final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
static Future<void> onDidReceiveBackgroundNotification(
NotificationResponse notificationResponse) async {}
static Future<void> init() async {
tz.initializeTimeZones();
const AndroidInitializationSettings androidInitializationSettings = AndroidInitializationSettings('@drawable/launcher_icon');
const DarwinInitializationSettings iOSInitializationSettings =
DarwinInitializationSettings();
const InitializationSettings initializationSettings = InitializationSettings(
android: androidInitializationSettings,
iOS: iOSInitializationSettings
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveBackgroundNotificationResponse: onDidReceiveBackgroundNotification,
onDidReceiveNotificationResponse: onDidReceiveBackgroundNotification,
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
?.requestExactAlarmsPermission();
}
static Future<void> scheduleReminderNotifications({
required String productName,
required DateTime reminderDate,
required String reminderTime,
required String operation,
required int id,
}) async {
List<String> timeParts = reminderTime.split(":");
final scheduledDate = DateTime(
reminderDate.year,
reminderDate.month,
reminderDate.day,
int.parse(timeParts[0]),
int.parse(timeParts[1]),
);
if (scheduledDate.isBefore(DateTime.now())) {
print("Scheduled date must be in the future.");
return;
}
print("Scheduling notification for: $reminderDate for id: $id");
if (operation == "update") {
print("Cancel existing notification for id $id");
await cancelNotification(id);
}
await _scheduleNotification(
id: id,
title: 'Attention: ${productName[0].toUpperCase() + productName.substring(1)} Expiration Alert',
body: 'Heads up! Your $productName will expire on ${scheduledDate.toString().split(" ")[0]}.',
scheduledDate: scheduledDate,
);
}
static Future<void> cancelNotification(int id) async {
await flutterLocalNotificationsPlugin.cancel(id);
}
static Future<void> _scheduleNotification({
required int id,
required String title,
required String body,
required DateTime scheduledDate,
}) async {
const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: AndroidNotificationDetails(
"channelId",
"channelName",
importance: Importance.high,
priority: Priority.high,
),
iOS: DarwinNotificationDetails(),
);
tzone.TZDateTime timeToset = tzone.TZDateTime.from(scheduledDate, tzone.local);
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
body,
timeToset,
platformChannelSpecifics,
uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
matchDateTimeComponents: DateTimeComponents.dateAndTime,
);
}
}
Chetan R is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
1