如何用Flutter Local Notifications实现28天周期规律通知?
可行性分析与实现方案
完全可行,借助Flutter Local Notifications插件的自定义调度能力,结合日期计算和本地存储,就能实现这种分段循环的周期通知功能。
核心逻辑
- 以28天为一个循环周期,用户设置X后,前X天按固定时段发送通知,剩余28-X天静默
- 每个周期结束后自动触发重置,从第1天开始新一轮循环
具体实现步骤
1. 初始化通知插件
先完成插件的基础初始化(Android/iOS的原生配置按官方要求完成即可,以下是Dart层代码):
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:shared_preferences/shared_preferences.dart'; final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin(); Future<void> initNotifications() async { const AndroidInitializationSettings androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); const DarwinInitializationSettings iosSettings = DarwinInitializationSettings(); const InitializationSettings initSettings = InitializationSettings( android: androidSettings, iOS: iosSettings, ); // 设置通知回调,处理周期重置 await _notificationsPlugin.initialize( initSettings, onDidReceiveNotificationResponse: (response) async { if (response.payload == 'reset_cycle') { final int userX = await _getUserX(); await _scheduleCycleNotifications(userX); } }, ); }
2. 调度周期内的通知
实现核心的通知调度函数,负责生成一个28天周期内的所有通知,并添加周期重置触发点:
// 调度一个完整周期的通知,X为用户设置的通知天数 Future<void> _scheduleCycleNotifications(int X) async { // 先清空旧通知,避免重复 await _notificationsPlugin.cancelAll(); final DateTime now = DateTime.now(); // 遍历28天,只在前X天安排通知 for (int dayOffset = 0; dayOffset < 28; dayOffset++) { if (dayOffset >= X) continue; // 设置每天固定发送时间,比如早上8点 DateTime scheduledTime = DateTime( now.year, now.month, now.day + dayOffset, 8, 0, ); // 如果当天的发送时间已过,顺延到次日 if (scheduledTime.isBefore(now)) { scheduledTime = scheduledTime.add(const Duration(days: 1)); } await _notificationsPlugin.schedule( dayOffset, // 用天数偏移量作为通知ID,避免重复 '周期提醒', '这是第${dayOffset + 1}天的通知', scheduledTime, const NotificationDetails( android: AndroidNotificationDetails( 'cycle_notif_channel', '周期通知频道', importance: Importance.max, priority: Priority.high, ), iOS: DarwinNotificationDetails(), ), payload: 'day_${dayOffset + 1}', ); } // 添加周期重置触发通知(静默,不打扰用户) final DateTime resetTime = now.add(const Duration(days: 28)); await _notificationsPlugin.schedule( 999, // 专属重置ID '', '', resetTime, const NotificationDetails( android: AndroidNotificationDetails( 'reset_channel', '周期重置频道', importance: Importance.low, priority: Priority.low, enableVibration: false, enableSound: false, ), iOS: DarwinNotificationDetails( presentAlert: false, presentSound: false, ), ), payload: 'reset_cycle', ); }
3. 处理用户设置与App重启
- 用SharedPreferences存储用户设置的X值,默认28天
- App启动时检查当前周期进度,重新调度未发送的通知:
// 获取用户设置的X值,默认28 Future<int> _getUserX() async { final prefs = await SharedPreferences.getInstance(); return prefs.getInt('notification_cycle_x') ?? 28; } // 保存用户修改的X值并重新调度通知 Future<void> updateUserX(int newX) async { final prefs = await SharedPreferences.getInstance(); await prefs.setInt('notification_cycle_x', newX); await _scheduleCycleNotifications(newX); } // App启动时调用,恢复通知调度 Future<void> restoreNotifications() async { final int userX = await _getUserX(); await _scheduleCycleNotifications(userX); }
关键注意点
- iOS权限:需要在
Info.plist中添加UIBackgroundModes并包含remote-notification,否则本地通知的后台触发可能失效 - 设备重启:本地通知在设备重启后会丢失,建议在
initState或App启动时调用restoreNotifications恢复调度 - 静默通知:重置用的通知要设置为无提示,避免干扰用户
内容的提问来源于stack exchange,提问作者WH LEE
相关产品推荐
相关产品推荐

