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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:30:58