Flutter本地通知每日重复相同内容问题求助
解决Flutter每日本地通知内容不更新的问题
你的问题核心在于使用了periodicallyShow方法——这个方法会一次性将初始传入的标题和内容缓存,后续重复推送时只会复用这些固定值,不会重新执行随机获取内容的逻辑。要实现每日不同的通知内容,需要改用定时触发任务+单次通知的方案,具体步骤如下:
1. 替换periodicallyShow为单次通知方法
首先修改你的NotificationService,添加一个单次显示通知的方法(原showNotification可以保留,但不再用它做周期推送):
Future<void> showSingleNotification(int id, String title, String body) async { await flutterLocalNotificationsPlugin.show( id, title, body, const NotificationDetails( android: AndroidNotificationDetails('main_channel', 'Main Channel', channelDescription: "notfi", importance: Importance.max, priority: Priority.max), iOS: DarwinNotificationDetails( sound: 'default.wav', presentAlert: true, presentBadge: true, presentSound: true, ), ), androidAllowWhileIdle: true, ); }
2. 使用后台定时任务触发每日通知
由于需要在App可能关闭的情况下仍能触发每日通知,推荐使用workmanager插件处理后台定时任务(支持Android和iOS)。
步骤2.1 添加依赖
在pubspec.yaml中添加:
dependencies: workmanager: ^0.5.1 shared_preferences: ^2.2.2 # 用来存储userPost,后台任务无法直接访问widget属性
步骤2.2 初始化Workmanager并编写任务回调
在main.dart中初始化Workmanager,编写后台任务的回调逻辑(这里会重新生成随机内容并显示通知):
import 'package:workmanager/workmanager.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { // 1. 初始化通知插件(后台任务中需重新初始化) final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); const DarwinInitializationSettings initializationSettingsIOS = DarwinInitializationSettings(); const InitializationSettings initializationSettings = InitializationSettings( android: initializationSettingsAndroid, iOS: initializationSettingsIOS); await flutterLocalNotificationsPlugin.initialize(initializationSettings); // 2. 随机获取通知内容 final List<String> names = ["内容1", "内容2", "内容3", "内容4"]; // 替换为你的列表 final random = Random(); final randomName = names[random.nextInt(names.length)]; // 3. 读取userPost(从本地存储获取,后台无法访问widget) final prefs = await SharedPreferences.getInstance(); final userPost = prefs.getString('user_post') ?? ''; // 4. 显示单次通知 await flutterLocalNotificationsPlugin.show( 1, '$randomName$userPost', randomName, const NotificationDetails( android: AndroidNotificationDetails('main_channel', 'Main Channel', channelDescription: "notfi", importance: Importance.max, priority: Priority.max), iOS: DarwinNotificationDetails( sound: 'default.wav', presentAlert: true, presentBadge: true, presentSound: true, ), ), androidAllowWhileIdle: true, ); return Future.value(true); }); } void main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化Workmanager await Workmanager().initialize( callbackDispatcher, isInDebugMode: false, // 发布版本设为false ); runApp(const MyApp()); }
步骤2.3 注册每日定时任务
修改按钮点击事件,将原来调用periodicallyShow的逻辑替换为注册每日任务(同时存储userPost到本地):
onPressed: () async { showToast(); // 1. 将userPost存储到本地,供后台任务读取 final prefs = await SharedPreferences.getInstance(); await prefs.setString('user_post', widget.userPost); // 2. 取消之前的任务(避免重复注册) await Workmanager().cancelAll(); // 3. 注册每日任务,比如每天早上8点触发 final now = DateTime.now(); DateTime scheduledTime = DateTime(now.year, now.month, now.day, 8, 0, 0); if (scheduledTime.isBefore(now)) { scheduledTime = scheduledTime.add(const Duration(days: 1)); } final initialDelay = scheduledTime.difference(now); await Workmanager().registerPeriodicTask( 'daily_notification_task', // 任务唯一标识 'daily_notification', // 任务名称(需和回调中对应) frequency: const Duration(days: 1), // 周期1天 initialDelay: initialDelay, // 第一次触发的延迟时间 constraints: const Constraints( networkType: NetworkType.not_required, // 不需要网络 ), ); },
3. 平台适配注意事项
- Android:需在
AndroidManifest.xml中添加后台权限和配置,确保应用在后台能被唤醒,具体参考workmanager官方文档。 - iOS:在
Info.plist中添加UIBackgroundModes,包含fetch和remote-notification;另外iOS的系统限制可能会影响定时任务的精准度,需要实际测试验证。
内容的提问来源于stack exchange,提问作者Marian
相关产品推荐
相关产品推荐

