You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter 通知开发:如何实现定时通知?

解决Flutter计时器通知调度的两个问题

一、获取准确的本地时区时间

你用tz.local得到的时间不准确,核心原因是没有正确关联设备的真实时区。需要结合flutter_native_timezone库获取设备时区标识符,再初始化timezone的位置:

  1. 先添加依赖到pubspec.yaml:
dependencies:
  flutter_local_notifications: ^16.1.0
  timezone: ^0.9.2
  flutter_native_timezone: ^2.0.0
  1. 初始化时区逻辑:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 18:35:20