Flutter 通知开发:如何实现定时通知?
解决Flutter计时器通知调度的两个问题
一、获取准确的本地时区时间
你用tz.local得到的时间不准确,核心原因是没有正确关联设备的真实时区。需要结合flutter_native_timezone库获取设备时区标识符,再初始化timezone的位置:
- 先添加依赖到
pubspec.yaml:
dependencies: flutter_local_notifications: ^16.1.0 timezone: ^0.9.2 flutter_native_timezone: ^2.0.0
- 初始化时区逻辑:
import 'package:timezone/data/latest_all.dart' as tz; import 'package:timezone/timezone.dart' as tz; import 'package:flutter_native_timezone/flutter_native_timezone.dart'; Future<void> initTimeZone() async { tz.initializeTimeZones(); final String timeZoneName = await FlutterNativeTimezone.getLocalTimezone(); tz.setLocalLocation(tz.getLocation(timeZoneName)); }
在APP启动时(比如main方法里)调用initTimeZone(),之后tz.local就能返回准确的本地时区时间。
二、解决zonedSchedule通知不触发的问题
要让通知正常触发,必须完成权限申请、初始化配置、渠道创建这几个关键步骤,具体如下:
1. 初始化通知插件
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); Future<void> initNotifications() async { // Android初始化配置 const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); // iOS初始化配置 const DarwinInitializationSettings initializationSettingsIOS = DarwinInitializationSettings( requestAlertPermission: true, requestBadgePermission: true, requestSoundPermission: true, ); const InitializationSettings initializationSettings = InitializationSettings( android: initializationSettingsAndroid, iOS: initializationSettingsIOS, ); await flutterLocalNotificationsPlugin.initialize(initializationSettings); }
在APP启动时调用这个初始化方法。
2. 申请通知权限
import 'dart:io'; Future<void> requestNotificationPermissions() async { if (Platform.isIOS) { await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< IOSFlutterLocalNotificationsPlugin>() ?.requestPermissions( alert: true, badge: true, sound: true, ); } else if (Platform.isAndroid) { final AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>(); await androidImplementation?.requestNotificationsPermission(); } }
可以在用户首次点击Launch按钮前,或者APP启动时申请权限。
3. 创建Android通知渠道(Android 8.0+必填)
Future<void> createNotificationChannel() async { const AndroidNotificationChannel channel = AndroidNotificationChannel( 'timer_channel', // 渠道ID,后续调度通知要匹配 '计时器通知', description: '计时器结束时的提醒通知', importance: Importance.high, ); final AndroidFlutterLocalNotificationsPlugin? androidImplementation = flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>(); await androidImplementation?.createNotificationChannel(channel); }
同样在初始化阶段调用这个方法。
4. 正确调度通知
假设计时器时长为Duration(minutes: 5),点击Launch按钮后执行以下代码:
void scheduleTimerNotification(Duration timerDuration) async { // 获取当前本地时区时间 final tz.TZDateTime now = tz.TZDateTime.now(tz.local); // 计算通知触发时间:当前时间 + 计时器时长 final tz.TZDateTime scheduledTime = now.add(timerDuration); const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'timer_channel', // 和创建的渠道ID保持一致 '计时器通知', channelDescription: '计时器结束提醒', priority: Priority.high, importance: Importance.high, ); const DarwinNotificationDetails iosDetails = DarwinNotificationDetails( sound: 'default', presentAlert: true, ); const NotificationDetails notificationDetails = NotificationDetails( android: androidDetails, iOS: iosDetails, ); // 调度通知 await flutterLocalNotificationsPlugin.zonedSchedule( 0, // 通知ID,可自定义 '计时器已结束', '你的计时器时间到了!', scheduledTime, notificationDetails, androidAllowWhileIdle: true, // 确保APP后台休眠时也能触发 uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, ); }
额外排查点
- 确保
scheduledTime是未来的时间,如果设置为过去的时间,通知不会触发 - Android端必须开启
androidAllowWhileIdle: true,否则APP在低功耗模式下可能无法触发通知 - iOS端需要在Xcode的Capabilities中开启Background Modes,并勾选Remote notifications
内容的提问来源于stack exchange,提问作者Bikbik
相关产品推荐
相关产品推荐

