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

Flutter使用workmanager与本地通知实现后台API触发告警超时问题

问题分析与解决方案

你当前的问题核心是在WorkManager任务里使用无限循环持续请求API,违反了Android/iOS后台任务的运行限制,系统会因为后台任务长时间运行直接终止进程,导致后续通知无法触发。WorkManager的设计定位是处理单次或周期性的短耗时任务,而非持续运行的后台进程。

具体修复方案

1. 替换长循环为周期性任务

把无限循环的持续轮询,改成WorkManager的周期性触发任务,每次任务只执行一次API请求和条件判断:

// 初始化WorkManager,配置周期性任务
void initWorkManager() {
  Workmanager().initialize(
    callbackDispatcher,
    isInDebugMode: true,
  );
  // 注册每15分钟触发一次的任务(系统允许的最小周期,不同平台有差异)
  Workmanager().registerPeriodicTask(
    'api_check_task',
    'apiCheck',
    frequency: const Duration(minutes: 15),
    existingWorkPolicy: ExistingWorkPolicy.replace,
  );
}

void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) async {
    try {
      // 单次API请求
      final response = await http.get(Uri.parse('你的API地址'));
      if (response.statusCode == 200) {
        final data = jsonDecode(response.body);
        // 判断条件是否满足
        if (data['目标字段'] == 触发条件) {
          // 后台环境需重新初始化通知服务
          final notificationService = NotificationService();
          await notificationService.init();
          notificationService.showNotification(告警标题, 告警内容);
        }
      }
    } catch (e) {
      // 捕获请求异常,避免任务直接失败
      print('API请求失败: $e');
      return Future.value(false);
    }
    return Future.value(true);
  });
}

2. 完善NotificationService的后台初始化

后台任务运行环境是隔离的,不能依赖主进程的初始化状态,需确保通知通道(Android)和权限(iOS)配置完成:

class NotificationService {
  final FlutterLocalNotificationsPlugin _plugin = FlutterLocalNotificationsPlugin();

  Future<void> init() async {
    // Android初始化配置
    const AndroidInitializationSettings androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
    // iOS初始化配置(申请通知权限)
    const IOSInitializationSettings iosInit = IOSInitializationSettings(
      requestAlertPermission: true,
      requestSoundPermission: true,
    );
    const InitializationSettings initSettings = InitializationSettings(
      android: androidInit,
      iOS: iosInit,
    );
    await _plugin.initialize(initSettings);

    // Android必须创建通知通道才能播放声音
    await _createAlertChannel();
  }

  Future<void> _createAlertChannel() async {
    const AndroidNotificationChannel channel = AndroidNotificationChannel(
      'alert_channel',
      '告警通知',
      description: '满足条件时触发声音告警',
      importance: Importance.max,
      sound: RawResourceAndroidNotificationSound('alert_sound'), // 自定义告警声音
      playSound: true,
    );
    await _plugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(channel);
  }

  void showNotification(String title, String body) async {
    const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
      'alert_channel',
      '告警通知',
      sound: RawResourceAndroidNotificationSound('alert_sound'),
      playSound: true,
    );
    const IOSNotificationDetails iosDetails = IOSNotificationDetails(
      sound: 'alert_sound.wav',
    );
    const NotificationDetails details = NotificationDetails(
      android: androidDetails,
      iOS: iosDetails,
    );
    await _plugin.show(0, title, body, details);
  }
}

3. 平台适配注意事项

  • Android:
    • Android 12及以上需在AndroidManifest.xml中添加POST_NOTIFICATIONS权限
    • 周期性任务最小间隔为15分钟(系统强制限制,无法设置更短)
    • 自定义声音文件需放在android/app/src/main/res/raw目录下
  • iOS:
    • 在Info.plist中开启Background Modes的Remote notifications或Background fetch权限
    • 自定义声音文件需放入项目资源,支持wav/aiff等格式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:31:16