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

Flutter每日定时通知:如何实现每日推送不同内容

问题:每日固定时间推送不同内容的通知

当前代码设置的每日重复通知只会发送首次选择的内容,需要修改实现每日内容不同的定时推送。

原代码

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  tz.initializeTimeZones();
  tz.setLocalLocation(tz.getLocation("Europe/Istanbul"));
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

  MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Bildirim Uygulaması'),
      ),
      body: Center(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () async {
                await _scheduleDailyNotification();
              },
              child: const Text('Günlük Bildirim Gönder'),
            ),
            ElevatedButton(
              onPressed: () async {
                await unScheduleAllNotifications();
              },
              child: const Text('iptal'),
            ),
          ],
        ),
      ),
    );
  }

  // Tüm zamanlanmış fonksiyonları iptal etme.
  Future unScheduleAllNotifications() async => await flutterLocalNotificationsPlugin.cancelAll();

  Future<void> _scheduleDailyNotification() async {
    var androidDetails = const AndroidNotificationDetails(
      'channelId',
      'channelName',
      importance: Importance.high,
    );

    var generalNotificationDetails = NotificationDetails(android: androidDetails);

    // Saat 10:00 için bir DateTime nesnesi oluştur
    tz.TZDateTime scheduledDate = tz.TZDateTime(
      tz.local,
      DateTime.now().year,
      DateTime.now().month,
      DateTime.now().day,
      20,
      38,
      1,
    );

    String selectedMessage = "ilk deger";
    int id = 1;

    // Eğer bu saat geçtiyse, bir sonraki gün için planla
    if (scheduledDate.isBefore(tz.TZDateTime.now(tz.local))) {
      print("bu kisim bakalim hep calisiyor mu olursa sorun aha burada lutfen ol");

      scheduledDate = scheduledDate.add(const Duration(days: 1));
      // Günlük bildirim içeriği listesi
      List<String> dailyMessages = [
        'Bugün harika bir gün!',
        'Yeni bir şeyler öğrenmeye hazır mısınız?',
        'Hayalinizdeki projeye başlama zamanı!',
        'Güzel anları değerlendirin!',
        'Bugün bir gülümsemeyle başlayın!',
      ];

      // Rastgele bir mesaj seç
      Random random = Random();
      final a = random.nextInt(dailyMessages.length);
      selectedMessage = dailyMessages[random.nextInt(dailyMessages.length)];
      id = a;
    }

    await flutterLocalNotificationsPlugin.zonedSchedule(
      id,
      'Günlük Hatırlatma',
      selectedMessage,
      scheduledDate,
      generalNotificationDetails,
      androidScheduleMode: AndroidScheduleMode.alarmClock,
      uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
      matchDateTimeComponents: DateTimeComponents.time,
    );
  }
}

问题原因

你使用了matchDateTimeComponents: DateTimeComponents.time来设置每日重复通知,但该参数会让系统以首次调度时的固定内容重复发送,无法动态更新通知内容。

解决方案

改为单次调度次日通知,并在通知触发后、应用启动时重新调度下一次通知,确保每次调度都生成新的随机内容。

修改后的代码

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  tz.initializeTimeZones();
  tz.setLocalLocation(tz.getLocation("Europe/Istanbul"));
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
  final List<String> _dailyMessages = [
    'Bugün harika bir gün!',
    'Yeni bir şeyler öğrenmeye hazır mısınız?',
    'Hayalinizdeki projeye başlama zamanı!',
    'Güzel anları değerlendirin!',
    'Bugün bir gülümsemeyle başlayın!',
  ];

  @override
  void initState() {
    super.initState();
    _initializeNotifications();
    // 应用启动时检查是否已调度通知,没有则立即调度
    _checkAndScheduleNotification();
  }

  // 初始化通知插件并设置回调
  Future<void> _initializeNotifications() async {
    const AndroidInitializationSettings initializationSettingsAndroid =
        AndroidInitializationSettings('@mipmap/ic_launcher');
    const InitializationSettings initializationSettings =
        InitializationSettings(android: initializationSettingsAndroid);
    
    await _flutterLocalNotificationsPlugin.initialize(
      initializationSettings,
      onDidReceiveNotificationResponse: (response) {
        // 用户点击通知后,重新调度次日通知
        _scheduleNextDailyNotification();
      },
    );

    // 监听通知触发事件(即使应用在后台)
    _flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails().then((details) {
      if (details?.didNotificationLaunchApp ?? false) {
        _scheduleNextDailyNotification();
      }
    });
  }

  // 检查是否已有待触发的通知,没有则调度
  Future<void> _checkAndScheduleNotification() async {
    List<PendingNotificationRequest> pendingRequests =
        await _flutterLocalNotificationsPlugin.pendingNotificationRequests();
    if (pendingRequests.isEmpty) {
      await _scheduleNextDailyNotification();
    }
  }

  // 取消所有已调度的通知
  Future<void> _cancelAllNotifications() async =>
      await _flutterLocalNotificationsPlugin.cancelAll();

  // 调度下一次的每日通知
  Future<void> _scheduleNextDailyNotification() async {
    const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
      'daily_notification_channel',
      '每日通知',
      importance: Importance.high,
      priority: Priority.high,
    );
    const NotificationDetails notificationDetails =
        NotificationDetails(android: androidDetails);

    // 计算目标时间(每天20:38:01)
    tz.TZDateTime scheduledDate = tz.TZDateTime(
      tz.local,
      DateTime.now().year,
      DateTime.now().month,
      DateTime.now().day,
      20,
      38,
      1,
    );

    // 如果当前时间已过目标时间,调度到次日
    if (scheduledDate.isBefore(tz.TZDateTime.now(tz.local))) {
      scheduledDate = scheduledDate.add(const Duration(days: 1));
    }

    // 随机选择通知内容
    final random = Random();
    final selectedMessage = _dailyMessages[random.nextInt(_dailyMessages.length)];
    final notificationId = random.nextInt(1000); // 使用随机ID避免冲突

    await _flutterLocalNotificationsPlugin.zonedSchedule(
      notificationId,
      'Günlük Hatırlatma',
      selectedMessage,
      scheduledDate,
      notificationDetails,
      androidScheduleMode: AndroidScheduleMode.alarmClock,
      uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
      // 移除重复调度参数,只调度单次通知
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Bildirim Uygulaması'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _scheduleNextDailyNotification,
              child: const Text('Günlük Bildirim Gönder'),
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: _cancelAllNotifications,
              child: const Text('İptal'),
            ),
          ],
        ),
      ),
    );
  }
}

关键改动说明

  1. 改为StatefulWidget:方便在initState中初始化通知并设置回调,监听通知交互。
  2. 移除重复调度参数:删除matchDateTimeComponents: DateTimeComponents.time,只调度单次通知。
  3. 动态生成内容:每次调度时都随机选择新的通知内容,确保每日内容不同。
  4. 通知回调处理:在用户点击通知或应用因通知启动时,自动调度次日的通知,形成循环。
  5. 启动时检查调度状态:应用启动时如果没有待触发的通知,立即调度下一次,避免遗漏。

内容的提问来源于stack exchange,提问作者suleyman gunes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 10:00:55