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

Flutter中Firebase Messaging后台处理器终止状态下API调用失败

应用终止状态下Firebase后台消息处理器中API调用卡住的解决方案

我开发了一款聊天消息应用,支持用户在前台、后台或终止状态下通过推送通知回复消息。但当应用处于终止状态时,firebaseMessagingBackgroundHandler中的API调用无法正常工作,程序卡在sendNotification函数处。

问题代码

后台事件处理代码

Future<void> 
 firebaseMessagingBackgroundHandler(RemoteMessage message) 
 async {
    await GetStorage.init();
    await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform);
    //Call HTTP request <Stuck here
    sendNotification(
      personUid,
      title,
      body,
      notificationTypeId,
      chatRoomId,
      userTokenDummy,
      userToken,
      serverKey,
      currentUserId,
      currentUserToken,
    );
  }

API请求代码

sendNotification({
    required String personUid,
    required String title,
    required String body,
    required int notificationTypeId,
    String? chatRoomId,
    String? userTokenDummy,
    String? userToken,
    String? serverKey,
    String? currentUserId,
    String? currentUserToken,
  }) async {
    try {
      final response = await http.post(
        Uri.parse('https://fcm.googleapis.com/fcm/send'),
        headers: <String, String>{
          HttpHeaders.contentTypeHeader: 
  'application/json',
          HttpHeaders.authorizationHeader: 'key=$serverKey'
        },
        body: jsonEncode(
          <String, dynamic>{
            "data": <String, dynamic>{
              "title": title,
              "body": body,
              "click_action": "FLUTTER_NOTIFICATION_CLICK",
              "id": "1",
              "status": "done",
              "senderId": currentUserId,
              "senderToken": currentUserToken,
              "notificationTypeId": notificationTypeId,
              "chatRoomId": chatRoomId,
            },
            "android": {
              "priority": "high",
            },
            "apns": {
              "headers": {"apns-priority": "10"}
            },
            "to": userToken,
            "content_available": true,
            "mutable-content": 1,
            "priority": "high",
          },
        ),
      );

      return response;
    } catch (e) {
      console(e.toString());
    }
  }

可能的原因

  • 系统后台限制:Android和iOS在应用终止状态下,对后台进程的网络访问、资源占用有严格管控,HTTP请求可能被系统拦截或无法获取足够资源完成请求。
  • 初始化阻塞:后台处理器中调用GetStorage.init()和Firebase.initializeApp()可能因为文件系统访问或异步初始化问题导致阻塞,进而卡住后续API调用。
  • 无超时机制:HTTP请求未设置超时时间,一旦网络环境不佳或请求目标无响应,会无限等待导致进程挂起。

修复方案

1. 简化后台初始化逻辑

避免在后台处理器中依赖本地存储(如GetStorage),直接从推送消息的data字段获取必要参数;同时优化Firebase初始化逻辑,避免重复初始化。

2. 给HTTP请求添加超时

为http.post设置合理的超时时间,防止请求无限阻塞。

3. 完善错误捕获与日志

确保所有异常都被捕获并输出日志,便于排查问题。

4. 配置必要的后台权限

  • Android:在AndroidManifest.xml中添加FOREGROUND_SERVICE权限,并确保FCM消息设置为高优先级。
  • iOS:在Xcode中开启Background Modes中的Remote notifications选项。

修改后的代码示例

优化后的后台事件处理器

Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // 从推送消息的data字段提取所需参数,避免依赖GetStorage
  final data = message.data;
  
  final personUid = data['personUid'] ?? '';
  final title = data['title'] ?? '';
  final body = data['body'] ?? '';
  final notificationTypeId = int.tryParse(data['notificationTypeId'] ?? '0') ?? 0;
  final chatRoomId = data['chatRoomId'];
  final userToken = data['userToken'];
  final serverKey = data['serverKey'];
  final currentUserId = data['currentUserId'];
  final currentUserToken = data['currentUserToken'];

  // 仅当Firebase未初始化时才执行初始化
  if (Firebase.apps.isEmpty) {
    await Firebase.initializeApp(
      options: DefaultFirebaseOptions.currentPlatform,
    );
  }

  try {
    // 添加超时机制,避免请求无限阻塞
    await sendNotification(
      personUid: personUid,
      title: title,
      body: body,
      notificationTypeId: notificationTypeId,
      chatRoomId: chatRoomId,
      userToken: userToken,
      serverKey: serverKey,
      currentUserId: currentUserId,
      currentUserToken: currentUserToken,
    ).timeout(const Duration(seconds: 10));
  } catch (e) {
    print('后台消息处理失败: $e');
  }
}

优化后的API请求函数

Future<http.Response?> sendNotification({
  required String personUid,
  required String title,
  required String body,
  required int notificationTypeId,
  String? chatRoomId,
  String? userTokenDummy,
  String? userToken,
  String? serverKey,
  String? currentUserId,
  String? currentUserToken,
}) async {
  try {
    final response = await http.post(
      Uri.parse('https://fcm.googleapis.com/fcm/send'),
      headers: <String, String>{
        HttpHeaders.contentTypeHeader: 'application/json',
        HttpHeaders.authorizationHeader: 'key=$serverKey',
      },
      body: jsonEncode(
        <String, dynamic>{
          "data": <String, dynamic>{
            "title": title,
            "body": body,
            "click_action": "FLUTTER_NOTIFICATION_CLICK",
            "id": "1",
            "status": "done",
            "senderId": currentUserId,
            "senderToken": currentUserToken,
            "notificationTypeId": notificationTypeId,
            "chatRoomId": chatRoomId,
          },
          "android": {"priority": "high"},
          "apns": {"headers": {"apns-priority": "10"}},
          "to": userToken,
          "content_available": true,
          "mutable-content": 1,
          "priority": "high",
        },
      ),
    ).timeout(const Duration(seconds: 10)); // 设置10秒超时

    return response;
  } catch (e) {
    print('发送通知失败: $e');
    return null;
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:50:41