如何使用flutter_local_notifications包在Flutter本地通知中显示当前日期,并实现无需打开APP的每日自动更新?
实现每日自动更新永久通知的日期(无需打开APP)
嘿,这个需求我之前做类似功能的时候踩过坑,其实结合flutter_local_notifications和后台定时任务插件就能完美解决,给你一步步说清楚怎么弄:
核心思路
要实现APP未启动时自动更新通知,光靠flutter_local_notifications不够——它只负责通知的展示,定时触发得靠专门的后台任务插件(比如workmanager)。我们的流程是:
- 用后台任务每天定时触发更新逻辑
- 更新时先取消旧的永久通知,再发送带当日日期的新永久通知
- 处理好平台权限和配置,确保后台任务能正常运行
步骤1:添加依赖
在pubspec.yaml里添加需要的包:
dependencies: flutter_local_notifications: ^16.1.0 # 用最新稳定版即可 workmanager: ^0.5.1 # 后台任务调度插件 intl: ^0.18.1 # 日期格式化工具
步骤2:初始化通知插件
先把flutter_local_notifications初始化好,确保能正常发送通知:
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:intl/intl.dart'; import 'package:workmanager/workmanager.dart'; import 'package:flutter/foundation.dart'; final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin(); Future<void> _initNotifications() async { // Android初始化配置 const AndroidInitializationSettings androidInitSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); // 替换成你的通知图标 // iOS初始化配置(可选,按需添加) const IOSInitializationSettings iosInitSettings = IOSInitializationSettings(); const InitializationSettings initSettings = InitializationSettings( android: androidInitSettings, iOS: iosInitSettings ); // 初始化插件 await _notificationsPlugin.initialize(initSettings); // iOS主动请求通知权限 if (kIsWeb == false && defaultTargetPlatform == TargetPlatform.iOS) { await _notificationsPlugin.requestPermissions( alert: true, badge: true, sound: true, ); } }
步骤3:配置后台定时任务
用workmanager注册一个每日重复的任务,用来触发通知更新:
// 后台任务的回调函数,必须是顶级函数或静态函数 void _backgroundTaskDispatcher() { Workmanager().executeTask((taskName, inputData) async { // 执行通知更新逻辑 await _updateDailyDateNotification(); return Future.value(true); // 返回true表示任务执行成功 }); } Future<void> _initWorkmanager() async { await Workmanager().initialize( _backgroundTaskDispatcher, isInDebugMode: false, // 发布版设为false ); // 注册每日重复任务,比如每天早上8点自动更新 await Workmanager().registerPeriodicTask( 'daily_date_notification_task', // 唯一任务ID,不能重复 'update_date_notification', // 任务标识,和回调内的taskName对应 frequency: const Duration(days: 1), // 重复周期为1天 initialDelay: Duration( hours: 8 - DateTime.now().hour, minutes: -DateTime.now().minute, seconds: -DateTime.now().second, ), // 计算距离下一个8点的延迟,若已过8点则自动延后到次日 constraints: const Constraints( networkType: NetworkType.not_required, // 无需网络也能执行 ), ); }
步骤4:实现通知更新逻辑
这里要注意:永久通知(ongoing: true)不能直接覆盖,必须先取消旧的,再发送新的:
Future<void> _updateDailyDateNotification() async { // 配置Android通知参数,设置为永久不可移除 const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'daily_date_channel_id', // 渠道ID,唯一值 '每日日期通知', // 渠道名称 channelDescription: '自动更新当前日期的永久通知', importance: Importance.max, priority: Priority.high, ongoing: true, // 关键:设置为永久不可移除状态 autoCancel: false, ); // iOS通知配置 const IOSNotificationDetails iosDetails = IOSNotificationDetails( presentAlert: true, presentBadge: false, ); const NotificationDetails notificationDetails = NotificationDetails( android: androidDetails, iOS: iosDetails ); // 先取消之前的通知(如果存在) await _notificationsPlugin.cancel(0); // 用固定的通知ID,比如0 // 格式化当前日期,可自定义格式 String currentDate = DateFormat('yyyy年MM月dd日 EEEE').format(DateTime.now()); // 发送新的永久通知 await _notificationsPlugin.show( 0, // 用同一个ID,确保替换旧通知 currentDate, // 通知标题显示日期 '今日日期', // 通知内容 notificationDetails, ); }
步骤5:在APP启动时初始化
在main函数里完成所有初始化,并且第一次启动就显示通知:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化通知和后台任务 await _initNotifications(); await _initWorkmanager(); // 首次启动先显示通知 await _updateDailyDateNotification(); runApp(const MyApp()); }
平台特殊配置
Android端
在android/app/src/main/AndroidManifest.xml里添加权限和Workmanager配置:
<!-- 添加必要权限 --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <application ...> <!-- 禁用Workmanager的自动初始化,避免冲突 --> <provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <meta-data android:name="androidx.work.WorkManagerInitializer" android:value="androidx.startup" tools:node="remove"/> </provider> <!-- 注册Workmanager服务 --> <service android:name="be.tramckrijte.workmanager.WorkmanagerService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="false"/> </application>
iOS端
在ios/Runner/Info.plist里添加后台模式权限:
<key>UIBackgroundModes</key> <array> <string>processing</string> </array>
注意事项
- 安卓API 26+对后台任务有严格限制,Workmanager会自动适配,但如果APP被用户强制关闭,任务可能暂停。
- iOS的后台任务触发间隔不一定完全精准,系统会根据设备状态调整,但基本能保证每日更新。
- 测试后台任务时,安卓可以用Workmanager的调试命令手动触发,iOS可以用Xcode的后台模拟功能。
内容的提问来源于stack exchange,提问作者Mr. ZeroOne
相关产品推荐
相关产品推荐

