Flutter实现每日9-17点随机内容定时离线通知的方案咨询
解决Flutter本地定时通知的两个核心问题
问题1:重复通知内容固定,无法随机生成
根源在于调用zonedSchedule时,通知内容就被固化存储了,后续重复触发不会重新执行NotificationRepo.getNotification方法获取新内容。
直接调整逻辑:放弃一次性设置重复通知,改成每次通知触发后,动态生成下一次的内容并调度:
- 初始只调度当天第一个待触发的通知(比如9:00),此时调用随机内容方法生成内容。
- 监听通知触发的回调(
onDidReceiveLocalNotification),每次触发后计算下一个小时的时间,若在9:00-17:00范围内,就调用zonedSchedule调度下一条通知,同时传入新的随机内容。 - 当天17:00的通知触发后,自动调度次日9:00的通知。
问题2:64条通知上限,无法提前数周排期
一次性提前排期会占用大量通知名额,直接用滚动调度解决:只保留当前待触发的1条通知,每次触发后再调度下一个,永远不会触及64条上限。
同时配合后台任务插件(如workmanager),在应用被杀死或设备重启后,自动在每天8:50左右触发任务,重新调度当天的通知,确保离线场景不中断。
具体代码示例
1. 初始调度逻辑
void scheduleDailyNotifications() async { final now = DateTime.now(); DateTime nextNotificationTime; // 确定当天第一个待触发的时间 if (now.hour < 9) { nextNotificationTime = DateTime(now.year, now.month, now.day, 9); } else if (now.hour >= 17) { nextNotificationTime = DateTime(now.year, now.month, now.day + 1, 9); } else { // 取当前小时的下一个整点 nextNotificationTime = DateTime(now.year, now.month, now.day, now.hour + 1); } await _scheduleSingleNotification(nextNotificationTime); } Future<void> _scheduleSingleNotification(DateTime scheduledTime) async { // 每次调度时才生成随机内容 final notificationContent = NotificationRepo.getNotification(notification.category); await flutterLocalNotificationsPlugin.zonedSchedule( 0, // 复用同一个ID,覆盖之前的待调度通知 "Promise", notificationContent, tz.TZDateTime.from(scheduledTime, tz.local), notificationDetails, androidAllowWhileIdle: true, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, // 不设置重复,手动控制下一次调度 matchDateTimeComponents: null, ); }
2. 监听通知触发并滚动调度
// 初始化插件时绑定回调 flutterLocalNotificationsPlugin.initialize( InitializationSettings( android: AndroidInitializationSettings('@mipmap/ic_launcher'), iOS: IOSInitializationSettings(), ), onDidReceiveLocalNotification: (id, title, body, payload) async { // 通知触发后立刻调度下一条 await _scheduleNextNotification(); }, ); Future<void> _scheduleNextNotification() async { final now = DateTime.now(); DateTime nextTime; if (now.hour >= 9 && now.hour < 17) { nextTime = DateTime(now.year, now.month, now.day, now.hour + 1); } else { // 当天时段结束,调度次日9点的通知 nextTime = DateTime(now.year, now.month, now.day + 1, 9); } await _scheduleSingleNotification(nextTime); }
3. 后台任务保障(避免应用被杀中断)
用workmanager设置每日定时任务,确保设备重启或应用被杀后,调度逻辑自动恢复:
void initializeWorkManager() async { await Workmanager().initialize( callbackDispatcher, isInDebugMode: false, ); // 每天8:50执行一次调度任务 await Workmanager().registerPeriodicTask( 'daily-notification-scheduler', 'schedule-notifications', frequency: Duration(days: 1), initialDelay: _getDelayToTargetTime(8, 50), ); } Duration _getDelayToTargetTime(int hour, int minute) { final now = DateTime.now(); final target = DateTime(now.year, now.month, now.day, hour, minute); return now.isAfter(target) ? target.add(Duration(days: 1)).difference(now) : target.difference(now); } // 后台回调函数 void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { if (task == 'schedule-notifications') { await scheduleDailyNotifications(); } return Future.value(true); }); }
内容的提问来源于stack exchange,提问作者luminous
相关产品推荐
相关产品推荐

