Flutter无需Firebase实现后台本地通知:按周动态触发
实现动态week值触发后台本地通知方案
要实现应用未打开时也能根据动态变化的week值触发本地通知,核心是利用系统级的后台任务调度机制(不能依赖应用自身后台存活,系统会主动回收闲置进程),同时确保能实时获取最新的week值生成对应通知内容。以下分iOS和Android平台给出具体实现方案:
iOS 实现步骤
- 申请通知权限:首先必须获取用户授权才能发送本地通知,可在应用启动时发起请求:
import UserNotifications func requestNotificationPermission() { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in if granted { // 权限获取成功,可后续调度通知 } } }
- 调度后台触发任务:有两种可靠方式实现周期性触发,结合
week值动态生成通知:- 日历触发器(适合自然周场景):如果
week对应日历周,可设置每周固定时间触发,触发时实时获取最新week值:
- 日历触发器(适合自然周场景):如果
func scheduleWeeklyCalendarNotification() { // 每周一9点触发的日历规则 let trigger = UNCalendarNotificationTrigger(dateMatching: DateComponents(weekday: 2, hour: 9), repeats: true) UNUserNotificationCenter.current().add(UNNotificationRequest(identifier: "WeeklyWeekReminder", content: UNMutableNotificationContent(), trigger: trigger)) } // 监听通知即将展示的回调,动态替换内容 func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { let updatedContent = UNMutableNotificationContent(contentsOf: notification.request.content)! let currentWeek = getCurrentWeek() // 自定义方法,获取最新week值 updatedContent.title = "周数提醒" updatedContent.body = "你处于第\(currentWeek)周" // 更新通知请求 let updatedRequest = UNNotificationRequest(identifier: notification.request.identifier, content: updatedContent, trigger: notification.request.trigger) center.add(updatedRequest) completionHandler([.alert, .sound]) }
- 后台刷新任务:允许应用在后台定期唤醒,主动获取
week值并触发通知,适合非固定周周期的场景:
// Info.plist中添加BGTaskSchedulerPermittedIdentifiers,值为"com.yourapp.weekRefreshTask" func registerBackgroundRefreshTask() { BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.yourapp.weekRefreshTask", using: nil) { task in self.handleWeekRefresh(task as! BGAppRefreshTask) } } func handleWeekRefresh(_ task: BGAppRefreshTask) { // 获取最新week值(从本地存储或接口) let currentWeek = getCurrentWeek() // 构建并发送通知 let content = UNMutableNotificationContent() content.title = "周数提醒" content.body = "你处于第\(currentWeek)周" content.sound = .default UNUserNotificationCenter.current().add(UNNotificationRequest(identifier: "WeekUpdate-\(currentWeek)", content: content, trigger: nil)) // 标记任务完成,避免系统限制后续后台任务 task.setTaskCompleted(success: true) // 调度下一次任务(一周后) let nextRequest = BGAppRefreshTaskRequest(identifier: "com.yourapp.weekRefreshTask") nextRequest.earliestBeginDate = Date().addingTimeInterval(7*24*60*60) try? BGTaskScheduler.shared.submit(nextRequest) }
Android 实现步骤
- 申请必要权限:在
AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
- 使用WorkManager调度后台任务:WorkManager是Android官方推荐的后台任务组件,可保证应用未运行、设备重启后仍能执行任务:
- 创建Worker类:处理通知发送逻辑:
class WeekNotificationWorker(context: Context, params: WorkerParameters) : Worker(context, params) { override fun doWork(): Result { // 获取最新week值(从SharedPreferences或接口) val currentWeek = getCurrentWeek() // 创建通知渠道(Android 8.0+必须) val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel("week_reminder_channel", "周数提醒", NotificationManager.IMPORTANCE_DEFAULT) notificationManager.createNotificationChannel(channel) } // 构建并发送通知 val notification = NotificationCompat.Builder(applicationContext, "week_reminder_channel") .setContentTitle("周数提醒") .setContentText("你处于第$currentWeek周") .setSmallIcon(R.drawable.ic_notification) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .build() notificationManager.notify(1, notification) // 调度下一次任务 scheduleWeeklyNotification(applicationContext) return Result.success() } }
- 调度周期性任务:
fun scheduleWeeklyNotification(context: Context) { val constraints = Constraints.Builder() .setRequiresBatteryNotLow(true) // 可选,低电时暂停任务 .build() val weeklyWork = PeriodicWorkRequestBuilder<WeekNotificationWorker>(7, TimeUnit.DAYS) .setConstraints(constraints) .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork( "WeekNotificationWork", ExistingPeriodicWorkPolicy.REPLACE, weeklyWork ) }
- 处理开机自启:确保设备重启后任务能重新调度,创建广播接收器:
class BootCompleteReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent?.action == Intent.ACTION_BOOT_COMPLETED) { context?.let { scheduleWeeklyNotification(it) } } } }
在AndroidManifest.xml注册接收器:
<receiver android:name=".BootCompleteReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
- 动态申请通知权限(Android 13+):
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1001) } }
通用注意事项
- week值的持久化:必须将
week值存储在本地(iOS的UserDefaults、Android的SharedPreferences)或通过接口实时获取,避免后台触发时无法拿到最新值。 - 避免硬编码内容:通知内容必须在触发任务的瞬间动态生成,不能提前固定,防止
week值更新后通知内容过时。 - 系统限制适配:iOS的后台刷新任务、Android的WorkManager都受系统资源(电量、内存)限制,若需要高精度触发,可结合应用启动时的通知更新逻辑作为补充。
内容的提问来源于stack exchange,提问作者faizy 313
相关产品推荐
相关产品推荐

