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

Flutter中Firebase Messaging通知解密问题:后台/终止状态失效

Flutter Firebase Messaging 后台/终止状态下加密消息解密解决方案

核心问题分析

后台/应用终止状态下,Firebase 通知消息会直接由系统级展示,默认不会触发 App 内的自定义逻辑——只有数据消息或带 data 字段的混合消息,才会在点击时触发 getInitialMessage/onMessageOpenedApp,或在后台时触发 onBackgroundMessage。你之前的代码没运行,大概率是消息格式不对,或后台处理逻辑配置不到位。


分步解决

1. 调整后端消息发送格式

必须把加密内容放在 data 字段中,而非 notification 的 body(系统会直接显示 notification.body,无法拦截解密)。示例请求体:

{
  "data": {
    "encrypted_content": "你的加密字符串",
    "sender_id": "123",
    "chat_id": "456"
  },
  "notification": {
    "title": "新消息",
    "body": "点击查看详情" // 这里只放通用提示,不要放加密内容
  },
  "priority": "high" // Android 后台消息必须设为 high 才能触发回调
}

2. 配置后台消息处理逻辑

后台状态下(App 在后台未终止),需要注册顶级全局函数处理消息,解密后手动显示本地通知:

// 注意:必须是顶级函数,不能是类方法,且只能用 Isolate 安全的 API
Future<void> firebaseBackgroundMessageHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  
  // 从 data 字段提取加密内容
  final encryptedMsg = message.data['encrypted_content'];
  // 执行解密逻辑(确保解密函数无 Flutter UI/插件依赖,比如不要用 shared_preferences)
  final decryptedMsg = yourDecryptFunction(encryptedMsg);
  
  // 手动调用本地通知插件显示解密后的内容
  await FlutterLocalNotificationsPlugin().show(
    int.parse(message.data['chat_id']),
    message.data['sender_name'] ?? "新消息",
    decryptedMsg,
    NotificationDetails(
      android: AndroidNotificationDetails(
        "chat_notification_channel",
        "聊天通知",
        importance: Importance.high,
      ),
      iOS: IOSNotificationDetails(),
    ),
  );
}

3. 初始化时注册回调

在 main 函数中完成初始化,覆盖终止/后台点击场景:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  
  // 注册后台消息处理器
  FirebaseMessaging.onBackgroundMessage(firebaseBackgroundMessageHandler);
  
  // 初始化本地通知插件(用于后台手动显示通知)
  await FlutterLocalNotificationsPlugin().initialize(
    InitializationSettings(
      android: AndroidInitializationSettings("@mipmap/ic_launcher"),
      iOS: IOSInitializationSettings(),
    ),
  );
  
  // 处理应用终止状态下点击通知启动的场景
  final initialMessage = await FirebaseMessaging.instance.getInitialMessage();
  if (initialMessage != null) {
    handleOpenedMessage(initialMessage);
  }
  
  // 处理后台状态下点击通知的场景
  FirebaseMessaging.onMessageOpenedApp.listen(handleOpenedMessage);
  
  runApp(MyApp());
}

// 处理通知点击后的逻辑(解密+跳转)
void handleOpenedMessage(RemoteMessage message) {
  final encryptedMsg = message.data['encrypted_content'];
  final decryptedMsg = yourDecryptFunction(encryptedMsg);
  
  // 跳转到聊天页面,传入解密后的消息
  Navigator.push(
    navigatorKey.currentContext!,
    MaterialPageRoute(
      builder: (context) => ChatScreen(message: decryptedMsg),
    ),
  );
}

4. 平台端配置

  • Android:

    1. 在 AndroidManifest.xml 中确保自定义 FirebaseMessagingService 配置(如果需要更底层的控制):
      <service
          android:name=".MyFirebaseMessagingService"
          android:exported="false">
          <intent-filter>
              <action android:name="com.google.firebase.MESSAGING_EVENT" />
          </intent-filter>
      </service>
      
    2. 确保消息优先级设为 high,否则 Android 12+ 会限制后台消息触发。
  • iOS:

    1. 在 Xcode 中开启 Background Modes 的 Remote notifications 选项。
    2. 在 Info.plist 中添加:
      <key>UIBackgroundModes</key>
      <array>
          <string>remote-notification</string>
      </array>
      

调试技巧

  • 用 Firebase 控制台发送测试消息时,选择「自定义数据」字段,填入加密内容,优先级设为高。
  • Android 用 adb logcat | grep FirebaseMessaging 查看消息接收日志,确认后台处理器是否执行。
  • iOS 用 Xcode 控制台查看 FIRMessaging 相关日志,排查消息是否到达。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 07:01:14