使用flutter_local_notifications时Flutter定时通知无法触发求助
Flutter定时通知无法触发问题排查(基于flutter_local_notifications)
我正尝试在Flutter应用中使用flutter_local_notifications包实现定时通知功能,即时通知可正常工作,但定时通知完全无法触发。请问我使用zonedSchedule调度通知的方式是否存在问题?
以下是我的代码:
import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/timezone.dart' as tz; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:permission_handler/permission_handler.dart'; class NotificationScreen extends Stateful Widget { @override _NotificationScreenState createState() => _NotificationScreenState(); } class _NotificationScreenState extends State<NotificationScreen> { final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); TimeOfDay? selectedTime; @override void initState() { super.initState(); _initializeNotifications(); } Future<void> _initializeNotifications() async { tz.initializeTimeZones(); // Timezone initialization const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); const InitializationSettings initializationSettings = InitializationSettings(android: initializationSettingsAndroid); await flutterLocalNotificationsPlugin.initialize(initializationSettings); // Request notification permission var status = await Permission.notification.status; if (status.isDenied) { status = await Permission.notification.request(); if (status.isPermanentlyDenied) { openAppSettings(); } } } Future<void> _scheduleNotification(TimeOfDay time) async { final now = DateTime.now(); DateTime scheduledDate = DateTime(now.year, now.month, now.day, time.hour, time.minute); if (scheduledDate.isBefore(now)) { scheduledDate = scheduledDate.add(const Duration(days: 1)); } tz.TZDateTime scheduledTime = tz.TZDateTime.from(scheduledDate, tz.local); print('Scheduled Time: $scheduledTime'); // Debugging output const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails( 'scheduled_notification_channel', 'Scheduled Notifications', channelDescription: 'Channel for scheduled notifications', importance: Importance.max, priority: Priority.high, ticker: 'ticker'); const NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails); await flutterLocalNotificationsPlugin.zonedSchedule( DateTime.now().millisecondsSinceEpoch ~/ 1000, // Unique ID 'Scheduled Notification', 'This is your reminder!', scheduledTime, notificationDetails, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, ); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Notification scheduled for ${time.format(context)}')), ); } Future<void> _sendInstantNotification() async { const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails( 'instant_notification_channel', 'Instant Notifications', channelDescription: 'Channel for instant notifications', importance: Importance.max, priority: Priority.high, ticker: 'ticker'); const NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails); await flutterLocalNotificationsPlugin.show( 1, 'Instant Notification', 'This is an instant notification!', notificationDetails); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Instant notification sent!'))); } Future<void> _pickTime() async { final TimeOfDay? picked = await showTimePicker( context: context, initialTime: TimeOfDay.now(), ); if (picked != null) { setState(() { selectedTime = picked; }); _scheduleNotification(picked); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Schedule Notification')), body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( selectedTime != null ? 'Selected Time: ${selectedTime!.format(context)}' : 'No Time Selected', style: const TextStyle(fontSize: 18), ), const SizedBox(height: 20), ElevatedButton( onPressed: _pickTime, child: const Text('Pick Time'), ), const SizedBox(height: 20), ElevatedButton( onPressed: _sendInstantNotification, child: const Text('Send Instant Notification'), ), ], ), ), ); } }
问题分析与修复方案
- 通知ID重复覆盖:原代码用秒级时间戳作为ID,短时间内多次调度会导致ID重复,直接覆盖之前的通知。建议改用递增整数ID或UUID生成唯一ID,避免冲突。
- 时区初始化不完整:仅调用
tz.initializeTimeZones()不足以确保时区正确,需添加tz.setLocalLocation(tz.getLocation('Asia/Shanghai'))(根据你的实际时区调整),保证tz.local指向正确时区,避免时间转换错误。 - Android电池优化限制:即使设置了
AndroidScheduleMode.exactAllowWhileIdle,部分国产厂商的电池优化仍会阻止后台定时任务。需添加ignoreBatteryOptimizations权限请求,并引导用户关闭应用的电池优化。 - 通知渠道未手动创建:Android 8.0+要求必须显式创建通知渠道,初始化时需调用
createNotificationChannel()确保渠道存在,否则通知无法显示。 - 调度时间验证:打印
scheduledTime确认转换后的时间是否符合预期,若时区设置错误,会导致通知在非预期时间触发或完全不触发。
内容的提问来源于stack exchange,提问作者asif ullah
相关产品推荐
相关产品推荐

