如何用flutter_local_notifications在Flutter中配置指定日期启停本地通知
配置Flutter本地每日通知并实现到期自动停止
问题说明
已通过flutter_local_notifications实现每日固定时间的本地通知,需求是让通知从2024年10月10日开始,到2024年11月15日自动停止,不清楚如何实现到期停止的功能。当前代码如下:
Future<void> scheduleDailyNotification(int id, String title, String body, DateTime dateTime) async { await _flutterLocalNotificationsPlugin.zonedSchedule( id, title, body, _nextInstanceOfTime(dateTime), medicationNotificationDetails(), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: DateTimeComponents.time, ); } tz.TZDateTime _nextInstanceOfTime(DateTime dateTime) { tz.initializeTimeZones(); var location = tz.getLocation(tz.local.currentTimeZone.abbreviation); tz.setLocalLocation(location); var scheduledDate = tz.TZDateTime.from(dateTime, location); return scheduledDate; }
解决方案
flutter_local_notifications没有直接支持重复通知到期停止的API,可通过以下两种方式实现:
方式1:预计算所有日期并逐个调度
计算从开始到结束日期之间每天的目标时间,为每一天单独调度通知。这种方式无需额外后台逻辑,所有通知提前排好,到期后自动停止。
修改后代码示例:
import 'package:timezone/timezone.dart' as tz; Future<void> scheduleDailyNotificationsUntilEndDate( int baseId, String title, String body, DateTime startTime, // 2024-10-10 目标时间 DateTime endDate, // 2024-11-15 ) async { tz.initializeTimeZones(); final location = tz.getLocation(tz.local.currentTimeZone.abbreviation); tz.setLocalLocation(location); // 转换为时区时间 var currentDate = tz.TZDateTime.from(startTime, location); final endTZDate = tz.TZDateTime(endDate.year, endDate.month, endDate.day, startTime.hour, startTime.minute, startTime.second, location); // 逐个调度每日通知 int notificationId = baseId; while (currentDate.isBefore(endTZDate.add(const Duration(days: 1)))) { await _flutterLocalNotificationsPlugin.zonedSchedule( notificationId, title, body, currentDate, medicationNotificationDetails(), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: null, // 无需自动重复 ); // 日期加一天 currentDate = currentDate.add(const Duration(days: 1)); notificationId++; } }
调用示例:
// 开始时间:2024-10-10 08:00:00 final startDateTime = DateTime(2024, 10, 10, 8, 0, 0); // 结束日期:2024-11-15 final endDate = DateTime(2024, 11, 15); await scheduleDailyNotificationsUntilEndDate(1, "每日提醒", "该做某事了", startDateTime, endDate);
方式2:触发通知时检查到期状态,手动控制重复
保留每日通知逻辑,但在通知触发回调中检查当前日期是否超过结束日期,已到期则取消调度,未到期则重新安排下一次通知。
步骤及代码示例:
- 初始化时配置通知触发回调
void initNotifications() async { // 初始化基础配置 await _flutterLocalNotificationsPlugin.initialize( InitializationSettings( android: AndroidInitializationSettings('@mipmap/ic_launcher'), iOS: IOSInitializationSettings( onDidReceiveLocalNotification: (id, title, body, payload) async { // iOS通知触发回调 await handleNotificationTrigger(id, title, body, payload); }, ), ), onDidReceiveNotificationResponse: (response) async { // Android通知触发/点击回调(根据插件版本选择) await handleNotificationTrigger(int.parse(response.id), response.notification?.title, response.notification?.body, response.payload); }, ); }
- 处理通知触发逻辑,控制是否继续调度
Future<void> handleNotificationTrigger(int id, String? title, String? body, String? payload) async { // 从payload解析结束日期,或直接使用预设值 final endDate = DateTime.parse(payload ?? "2024-11-15"); final now = DateTime.now(); if (now.isAfter(endDate)) { // 已到期,取消后续调度 await _flutterLocalNotificationsPlugin.cancel(id); return; } // 未到期,调度下一次通知 final nextTime = _nextInstanceOfTime(DateTime(now.year, now.month, now.day, 8, 0, 0).add(const Duration(days: 1))); await _flutterLocalNotificationsPlugin.zonedSchedule( id, title, body, nextTime, medicationNotificationDetails(), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: null, payload: endDate.toIso8601String(), ); }
- 修改初始调度方法,仅安排第一次通知
Future<void> scheduleDailyNotificationUntilEnd(int id, String title, String body, DateTime startTime, DateTime endDate) async { final firstTime = _nextInstanceOfTime(startTime); if (firstTime.isAfter(endDate)) return; await _flutterLocalNotificationsPlugin.zonedSchedule( id, title, body, firstTime, medicationNotificationDetails(), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: null, // 关闭自动重复 payload: endDate.toIso8601String(), ); }
两种方式对比
- 方式1:实现简单,无需处理回调,适合通知天数较少的场景;缺点是天数过多时会占用较多系统资源。
- 方式2:资源占用低,适合长期但需到期停止的场景;缺点是需要处理平台特定的回调逻辑,相对复杂。
内容的提问来源于stack exchange,提问作者Rapkat Baudunov
相关产品推荐
相关产品推荐

