Flutter(Android):如何在通知生成时自动执行后台代码
问题描述
我正在使用flutter_local_notification和workmanager插件,旨在通知生成时运行后台代码(仅针对Android平台)。以下是flutter_local_notification的初始化代码:
final StreamController<ReceivedNotification> didReceiveLocalNotificationSubject = StreamController<ReceivedNotification>.broadcast(); Future<void> init() async { await _configureLocalTimeZone(); notificationAppLaunchDetails = await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails(); if (notificationAppLaunchDetails!.didNotificationLaunchApp) { selectedNotificationPayload = notificationAppLaunchDetails!.notificationResponse?.payload; } const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); InitializationSettings initializationSettings = const InitializationSettings( android: initializationSettingsAndroid, ); await flutterLocalNotificationsPlugin.initialize( initializationSettings, onDidReceiveNotificationResponse: (NotificationResponse notificationResponse) { switch (notificationResponse.notificationResponseType) { case NotificationResponseType.selectedNotification: case NotificationResponseType.selectedNotificationAction: // if (notificationResponse.actionId == navigationActionId) { selectNotificationSubject.add(notificationResponse.payload); selectedNotificationPayload = notificationResponse.payload; // } didReceiveLocalNotificationSubject.add( ReceivedNotification( id: notificationResponse.id!, title: notificationResponse.actionId, body: 'stuff', payload: notificationResponse.payload, ), ); break; } }, // onDidReceiveBackgroundNotificationResponse: notificationTapBackground, ); _notificationsEnabled = await _isAndroidPermissionGranted(); _notificationsEnabled = await _requestPermissions(); _configureDidReceiveLocalNotificationSubject(); }
这是Workmanager执行的代码:
void _configureDidReceiveLocalNotificationSubject() { didReceiveLocalNotificationSubject.stream .listen((ReceivedNotification receivedNotification) async { var title = receivedNotification.title ?? 'UNKNOWN'; Workmanager().registerOneOffTask( "my.simpleTask", "my.simpleTask", inputData: <String, dynamic>{ 'string': title, }, ); }); }
目前我的代码存在两个问题:
- Workmanager任务仅在用户点击通知时才会运行
- 如果用户先终止应用,即使通知生成(并被点击),Workmanager任务也不会执行
如何让Workmanager任务在通知生成时立即执行(无需用户点击),且无论应用是否终止都能生效?
解决方案
一、让Workmanager在通知生成时立即执行(无需点击)
当前逻辑依赖通知点击回调触发任务,要实现通知生成即执行任务,需根据通知类型调整触发时机:
1. 手动触发的即时通知
如果是主动调用show()显示通知,直接在调用show()的代码后同步注册Workmanager任务:
// 显示通知 await flutterLocalNotificationsPlugin.show( id, title, body, notificationDetails, payload: payload, ); // 同时注册后台任务(用通知ID做任务名后缀,避免重复注册) await Workmanager().registerOneOffTask( "my.simpleTask_$id", "my.simpleTask", inputData: <String, dynamic>{ 'string': title ?? 'UNKNOWN', }, existingWorkPolicy: ExistingWorkPolicy.replace, );
2. 定时/延迟通知
如果是用zonedSchedule()设置的定时通知,利用flutter_local_notifications的后台回调,在通知触发时直接启动任务:
- 先定义一个顶级静态回调函数(必须加
@pragma('vm:entry-point')防止被编译优化移除):
@pragma('vm:entry-point') void onNotificationTriggered(NotificationResponse response) { Workmanager().registerOneOffTask( "my.simpleTask_${response.id}", "my.simpleTask", inputData: <String, dynamic>{ 'string': response.payload ?? 'UNKNOWN', }, ); }
- 在初始化
flutterLocalNotificationsPlugin时配置该回调:
await flutterLocalNotificationsPlugin.initialize( initializationSettings, onDidReceiveNotificationResponse: (response) { // 保留原有的点击回调逻辑 }, onDidReceiveBackgroundNotificationResponse: onNotificationTriggered, // 新增后台触发回调 );
这个回调会在通知显示时自动执行,无需用户点击,即使应用在后台或被终止。
二、保证应用终止后Workmanager任务仍能执行
Workmanager本身支持应用终止后执行任务,但需做好以下配置:
1. 正确初始化Workmanager
在main()函数启动时就初始化Workmanager,注册顶级任务处理函数:
@pragma('vm:entry-point') void taskCallbackDispatcher() { Workmanager().executeTask((task, inputData) { // 这里写你的后台任务逻辑 String title = inputData?['string'] ?? 'UNKNOWN'; print("后台任务执行:$title"); return Future.value(true); // 返回true表示任务成功,false会触发重试 }); } void main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化Workmanager await Workmanager().initialize( taskCallbackDispatcher, isInDebugMode: kDebugMode, ); // 其他初始化逻辑(如flutter_local_notifications) runApp(const MyApp()); }
2. 适配系统权限与限制
- 确保已获取
POST_NOTIFICATIONS权限(你的代码中已处理,需确认权限申请成功) - 针对国产ROM(小米、华为等),需引导用户开启「自启动权限」和「后台运行权限」,否则系统可能会杀死Workmanager进程
3. 任务标识与重复策略
注册任务时使用唯一的taskName(如拼接通知ID),并设置existingWorkPolicy避免重复注册导致任务失效。
关键注意事项
- 所有后台回调函数(
taskCallbackDispatcher、onNotificationTriggered)必须是顶级或静态函数,且添加@pragma('vm:entry-point')注解,防止被Flutter编译优化移除 - Workmanager的任务调度受Android电池优化策略影响,无法保证绝对实时;若需严格实时操作,可考虑使用前台服务,但会增加电量消耗
内容的提问来源于stack exchange,提问作者Randomize
相关产品推荐
相关产品推荐

