使用flutter_local_notifications插件Flutter定时通知无法触发求助
Flutter定时通知不触发问题排查与解决(Android 10)
问题描述
使用flutter_local_notifications开发定时通知功能时,即时通知可正常触发,但定时通知未按预期显示,调试控制台无任何报错或警告。
环境信息
- flutter_local_notifications版本:^19.0.0
- 运行平台:Android 10
实现代码
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_timezone/flutter_timezone.dart'; import 'package:timezone/timezone.dart' as tz; import 'package:timezone/data/latest.dart' as tz; class NotificationService { final notificationsPlugin = FlutterLocalNotificationsPlugin(); bool _isInitialized = false; bool get isInitialized => _isInitialized; // Initialize Future<void> initNotification() async { if (_isInitialized) return; // Initialize timezone tz.initializeTimeZones(); final String currentTimeZone = await FlutterTimezone.getLocalTimezone(); tz.setLocalLocation(tz.getLocation(currentTimeZone)); print("Device Timezone: $currentTimeZone"); const initSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); const initSettings = InitializationSettings(android: initSettingsAndroid); await notificationsPlugin.initialize(initSettings); _isInitialized = true; } // Notification Detail NotificationDetails notificationDetails() { return NotificationDetails( android: AndroidNotificationDetails( 'daily_channel_id', 'Daily Notifications', channelDescription: 'Daily notifications for the app', importance: Importance.max, priority: Priority.high, ), ); } // Show Notifications Future<void> showNotifications({ int id = 0, String? title, String? body, }) async { return notificationsPlugin.show( id, title, body, notificationDetails(), ); } // Schedule a notification at a specified time (hour: 0-23, min: 0-59) Future<void> scheduleNotification({ int id = 1, required String title, required String body, required int hour, required int minute, }) async { // Get the current date/time in device's local timezone final now = tz.TZDateTime.now(tz.local); print("Current Time (TZ): $now"); // Create a date time for today at the specified hour and minute var scheduledDate = tz.TZDateTime( tz.local, now.year, now.month, now.day, hour, minute, ); print("Scheduled Time (Before Adjustment): $scheduledDate"); // Ensure scheduled time is in the future if (scheduledDate.isBefore(now)) { scheduledDate = scheduledDate.add(Duration(days: 1)); print("Scheduled Time Adjusted to Next Day: $scheduledDate"); } // Schedule the notification await notificationsPlugin.zonedSchedule( id, title, body, scheduledDate, notificationDetails(), androidScheduleMode: AndroidScheduleMode.inexactAllowWhileIdle, matchDateTimeComponents: DateTimeComponents.dateAndTime, ); print("Final Scheduled Time: $scheduledDate"); } // Cancel all notifications Future<void> cancelAllNotifications() async { await notificationsPlugin.cancelAll(); } }
已完成排查
- 调用
showNotifications方法触发即时通知功能正常 - 调用
scheduleNotification方法后,控制台打印的定时时间计算正确,但通知未按时出现 - 已通过
flutter_timezone和timezone包正确识别并设置设备时区 - 应用已具备通知权限(Android 10无需额外精确闹钟权限)
- 应用未被电池优化限制后台进程
针对性解决方案
1. 调整定时精度模式
当前使用的AndroidScheduleMode.inexactAllowWhileIdle模式下,系统可能会合并延迟通知以节省电量。如果需要精确触发,改为AndroidScheduleMode.exactAllowWhileIdle,该模式支持设备在低电模式下仍精确触发通知:
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
2. 修正重复触发参数(按需选择)
- 如果需求是每天固定时间重复触发,将
matchDateTimeComponents改为DateTimeComponents.time(原代码的dateAndTime仅会触发一次指定日期时间) - 如果是单次定时触发,保持
DateTimeComponents.dateAndTime即可
3. 添加必填时间解释参数
在zonedSchedule中补充uiLocalNotificationDateInterpretation参数,明确时间解析方式:
uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
4. 主动创建通知渠道(可选)
虽然代码中定义了渠道,但部分场景下渠道可能未自动创建,可在初始化时主动创建:
// 在initNotification方法中添加 await notificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(AndroidNotificationChannel( 'daily_channel_id', 'Daily Notifications', description: 'Daily notifications for the app', importance: Importance.max, ));
修改后的scheduleNotification方法示例
Future<void> scheduleNotification({ int id = 1, required String title, required String body, required int hour, required int minute, }) async { final now = tz.TZDateTime.now(tz.local); var scheduledDate = tz.TZDateTime( tz.local, now.year, now.month, now.day, hour, minute, ); if (scheduledDate.isBefore(now)) { scheduledDate = scheduledDate.add(const Duration(days: 1)); } await notificationsPlugin.zonedSchedule( id, title, body, scheduledDate, notificationDetails(), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, matchDateTimeComponents: DateTimeComponents.time, // 每天重复触发用这个,单次用dateAndTime uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, ); }
内容的提问来源于stack exchange,提问作者Kavindu Dilhara
相关产品推荐
相关产品推荐

