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

如何用flutter_local_notifications在Flutter中配置指定日期启停本地通知

配置Flutter本地每日通知并实现到期自动停止

问题说明

已通过flutter_local_notifications实现每日固定时间的本地通知,需求是让通知从2024年10月10日开始,到2024年11月15日自动停止,不清楚如何实现到期停止的功能。当前代码如下:

Future<void> scheduleDailyNotification(int id, String title, String body, DateTime dateTime) async {
    await _flutterLocalNotificationsPlugin.zonedSchedule(
      id,
      title,
      body,
      _nextInstanceOfTime(dateTime),
      medicationNotificationDetails(),
      androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
      uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
      matchDateTimeComponents: DateTimeComponents.time,
    );
  }


 tz.TZDateTime _nextInstanceOfTime(DateTime dateTime) {
    tz.initializeTimeZones();
    var location = tz.getLocation(tz.local.currentTimeZone.abbreviation);
    tz.setLocalLocation(location);
    var scheduledDate = tz.TZDateTime.from(dateTime, location);
    return scheduledDate;
  }

解决方案

flutter_local_notifications没有直接支持重复通知到期停止的API,可通过以下两种方式实现:

方式1:预计算所有日期并逐个调度

计算从开始到结束日期之间每天的目标时间,为每一天单独调度通知。这种方式无需额外后台逻辑,所有通知提前排好,到期后自动停止。

修改后代码示例:

import 'package:timezone/timezone.dart' as tz;

Future<void> scheduleDailyNotificationsUntilEndDate(
    int baseId,
    String title,
    String body,
    DateTime startTime, // 2024-10-10 目标时间
    DateTime endDate,   // 2024-11-15
  ) async {
  tz.initializeTimeZones();
  final location = tz.getLocation(tz.local.currentTimeZone.abbreviation);
  tz.setLocalLocation(location);

  // 转换为时区时间
  var currentDate = tz.TZDateTime.from(startTime, location);
  final endTZDate = tz.TZDateTime(endDate.year, endDate.month, endDate.day, startTime.hour, startTime.minute, startTime.second, location);

  // 逐个调度每日通知
  int notificationId = baseId;
  while (currentDate.isBefore(endTZDate.add(const Duration(days: 1)))) {
    await _flutterLocalNotificationsPlugin.zonedSchedule(
      notificationId,
      title,
      body,
      currentDate,
      medicationNotificationDetails(),
      androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
      uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
      matchDateTimeComponents: null, // 无需自动重复
    );
    // 日期加一天
    currentDate = currentDate.add(const Duration(days: 1));
    notificationId++;
  }
}

调用示例:

// 开始时间:2024-10-10 08:00:00
final startDateTime = DateTime(2024, 10, 10, 8, 0, 0);
// 结束日期:2024-11-15
final endDate = DateTime(2024, 11, 15);
await scheduleDailyNotificationsUntilEndDate(1, "每日提醒", "该做某事了", startDateTime, endDate);

方式2:触发通知时检查到期状态,手动控制重复

保留每日通知逻辑,但在通知触发回调中检查当前日期是否超过结束日期,已到期则取消调度,未到期则重新安排下一次通知。

步骤及代码示例:

  1. 初始化时配置通知触发回调
void initNotifications() async {
  // 初始化基础配置
  await _flutterLocalNotificationsPlugin.initialize(
    InitializationSettings(
      android: AndroidInitializationSettings('@mipmap/ic_launcher'),
      iOS: IOSInitializationSettings(
        onDidReceiveLocalNotification: (id, title, body, payload) async {
          // iOS通知触发回调
          await handleNotificationTrigger(id, title, body, payload);
        },
      ),
    ),
    onDidReceiveNotificationResponse: (response) async {
      // Android通知触发/点击回调(根据插件版本选择)
      await handleNotificationTrigger(int.parse(response.id), response.notification?.title, response.notification?.body, response.payload);
    },
  );
}
  1. 处理通知触发逻辑,控制是否继续调度
Future<void> handleNotificationTrigger(int id, String? title, String? body, String? payload) async {
  // 从payload解析结束日期,或直接使用预设值
  final endDate = DateTime.parse(payload ?? "2024-11-15");
  final now = DateTime.now();

  if (now.isAfter(endDate)) {
    // 已到期,取消后续调度
    await _flutterLocalNotificationsPlugin.cancel(id);
    return;
  }

  // 未到期,调度下一次通知
  final nextTime = _nextInstanceOfTime(DateTime(now.year, now.month, now.day, 8, 0, 0).add(const Duration(days: 1)));
  await _flutterLocalNotificationsPlugin.zonedSchedule(
    id,
    title,
    body,
    nextTime,
    medicationNotificationDetails(),
    androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
    uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
    matchDateTimeComponents: null,
    payload: endDate.toIso8601String(),
  );
}
  1. 修改初始调度方法,仅安排第一次通知
Future<void> scheduleDailyNotificationUntilEnd(int id, String title, String body, DateTime startTime, DateTime endDate) async {
  final firstTime = _nextInstanceOfTime(startTime);
  if (firstTime.isAfter(endDate)) return;

  await _flutterLocalNotificationsPlugin.zonedSchedule(
    id,
    title,
    body,
    firstTime,
    medicationNotificationDetails(),
    androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
    uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
    matchDateTimeComponents: null, // 关闭自动重复
    payload: endDate.toIso8601String(),
  );
}

两种方式对比

  • 方式1:实现简单,无需处理回调,适合通知天数较少的场景;缺点是天数过多时会占用较多系统资源。
  • 方式2:资源占用低,适合长期但需到期停止的场景;缺点是需要处理平台特定的回调逻辑,相对复杂。

内容的提问来源于stack exchange,提问作者Rapkat Baudunov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:45:09