Flutter中如何实现每日不同时间的定时重复通知?
实现Flutter每日动态时间推送通知方案
核心思路
periodicallyShow仅支持固定间隔重复推送,无法满足每日不同时间的需求,因此采用单次预约+触发后自动预约下一次的模式:
- 每次仅预约当日未到时间或次日的单次通知
- 通知触发时,立即生成下一日的推送时间并完成预约
- APP启动时自动检查并补预约当日通知
代码修改与实现
1. 新增动态时间生成方法
根据需求生成下一次推送时间,示例为随机生成6-22点的任意时间,可替换为自定义规则(如从预设时间列表选取):
// 生成下一个推送时间:若当前时间已过当日目标时间,则顺延至次日 tz.TZDateTime _getNextNotificationTime() { final now = tz.TZDateTime.now(tz.local); // 随机生成6-22点之间的小时和分钟 final randomHour = Random().nextInt(17) + 6; final randomMinute = Random().nextInt(60); var scheduledDate = tz.TZDateTime( tz.local, now.year, now.month, now.day, randomHour, randomMinute, ); // 若当前时间已过当日预约时间,自动推至次日 if (scheduledDate.isBefore(now)) { scheduledDate = scheduledDate.add(const Duration(days: 1)); } return scheduledDate; }
2. 重构单次通知调度方法
封装单次预约逻辑,确保通知配置统一:
static Future _scheduleSingleNotification({ required int id, required String title, required String body, required String payload, required tz.TZDateTime scheduledTime, }) async { const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'daily_dynamic_channel', '每日动态通知', channelDescription: '每天不同时间推送的通知频道', importance: Importance.max, priority: Priority.high, ); const NotificationDetails notificationDetails = NotificationDetails(android: androidDetails); await _flutterLocalNotificationsPlugin.zonedSchedule( id, title, body, scheduledTime, notificationDetails, androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, payload: payload, ); }
3. 完善通知触发回调
在通知触发后自动预约下一次推送:
static void onNotificationTap(NotificationResponse notificationResponse) { onClickNotification.add(notificationResponse.payload!); // 通知触发后立即预约下一日的通知 scheduleNextDailyNotification( title: "每日提醒", body: "今日提醒已送达", payload: "daily_notification_payload", ); }
4. 新增首次预约入口方法
用于APP启动时初始化首次通知预约:
static Future scheduleNextDailyNotification({ required String title, required String body, required String payload, }) async { tz.initializeTimeZones(); final nextTime = _getNextNotificationTime(); // 用日期拼接成唯一ID,避免重复预约 final notificationId = int.parse("${nextTime.year}${nextTime.month}${nextTime.day}"); await _scheduleSingleNotification( id: notificationId, title: title, body: body, payload: payload, scheduledTime: nextTime, ); }
5. 启动时自动初始化预约
在原有init方法末尾添加首次预约逻辑:
static Future init() async { // 保留原有的初始化代码... await _flutterLocalNotificationsPlugin.initialize(initializationSettings, onDidReceiveNotificationResponse: onNotificationTap, onDidReceiveBackgroundNotificationResponse: onNotificationTap); // APP启动时自动预约下一次通知 await scheduleNextDailyNotification( title: "每日提醒", body: "新的一天提醒已安排", payload: "initial_daily_payload", ); }
关键注意事项
- 时区处理:必须使用
tz包的TZDateTime,避免时区偏差导致通知时间错误 - 通知ID唯一性:每日使用不同ID(如日期拼接),防止覆盖未触发的预约
- 安卓权限配置:在
AndroidManifest.xml中添加精确闹钟权限:<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <uses-permission android:name="android.permission.USE_EXACT_ALARM" /> - 后台回调配置:确保
onDidReceiveBackgroundNotificationResponse正常工作,保证APP后台时也能自动预约下一次通知
内容的提问来源于stack exchange,提问作者Auvee
相关产品推荐
相关产品推荐

