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

Flutter iOS应用终止时如何实现FCM数据消息推送通知?

解决Flutter iOS应用终止后无法接收FCM Data消息的问题

核心原因说明

iOS系统对纯FCM Data消息的处理有严格限制:当APP处于终止状态时,纯Data消息不会触发系统唤醒APP,也不会显示通知。只有同时包含notification和data字段的混合推送消息,才会由APNs在通知栏展示,用户点击后才会将data传递给APP。这是iOS系统的原生限制,第三方插件无法绕过。


方案一:Flutter纯FCM配置优化

1. 调整推送消息结构

发送推送时必须同时包含notification和data字段,示例Payload:

{
  "to": "/topics/your_topic",
  "notification": {
    "title": "通知标题",
    "body": "通知内容"
  },
  "data": {
    "key1": "value1",
    "key2": "value2"
  },
  "apns": {
    "payload": {
      "aps": {
        "content-available": 1
      }
    }
  }
}
  • content-available: 1用于触发后台刷新,确保后台状态下能正常接收数据。

2. 完善FCM插件配置

使用官方firebase_messaging插件,确保以下配置正确:

  • 在Info.plist中添加后台权限配置:
    <key>UIBackgroundModes</key>
    <array>
      <string>remote-notification</string>
    </array>
    <key>FirebaseAppDelegateProxyEnabled</key>
    <false/>
    
  • 配置后台消息处理器与初始化逻辑:
    Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
      await Firebase.initializeApp();
      print('收到后台消息: ${message.data}');
      // 这里添加自定义消息处理逻辑
    }
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp();
      FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
      
      // 请求完整推送权限(必须包含alert)
      NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
        alert: true,
        badge: true,
        sound: true,
      );
      
      // 订阅目标主题
      await FirebaseMessaging.instance.subscribeToTopic('your_topic');
      
      runApp(MyApp());
    }
    
  • 监听APP从终止状态被通知唤醒的情况:
    @override
    void initState() {
      super.initState();
      FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
        if (message != null) {
          print('终止状态启动收到数据: ${message.data}');
          // 跳转对应页面或执行业务逻辑
        }
      });
    }
    

方案二:Swift原生结合Method Channel实现

如果插件配置后仍存在问题,可通过原生代码直接处理推送,再将数据传递给Flutter:

1. 原生端配置(Swift)

修改AppDelegate.swift

import UIKit
import Flutter
import FirebaseMessaging
import UserNotifications

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    FirebaseApp.configure()
    
    // 请求推送权限
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
      if granted {
        DispatchQueue.main.async {
          application.registerForRemoteNotifications()
        }
      }
    }
    
    // 处理APP终止状态下由通知启动的情况
    if let remoteNotification = launchOptions?[.remoteNotification] as? [String: Any] {
      let channel = FlutterMethodChannel(name: "com.example.push_handler", binaryMessenger: window?.rootViewController as! FlutterBinaryMessenger)
      channel.invokeMethod("receivePushData", arguments: remoteNotification)
    }
    
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  // 处理后台/前台收到的推送
  override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    let channel = FlutterMethodChannel(name: "com.example.push_handler", binaryMessenger: window?.rootViewController as! FlutterBinaryMessenger)
    channel.invokeMethod("receivePushData", arguments: userInfo)
    completionHandler(.newData)
  }
  
  // 绑定APNs Token到FCM并订阅主题
  override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    Messaging.messaging().apnsToken = deviceToken
    Messaging.messaging().subscribe(toTopic: "your_topic") { error in
      if let error = error {
        print("订阅主题失败: \(error.localizedDescription)")
      } else {
        print("订阅主题成功")
      }
    }
  }
}

2. Flutter端监听Method Channel

class _MyAppState extends State<MyApp> {
  late MethodChannel _pushChannel;

  @override
  void initState() {
    super.initState();
    _pushChannel = MethodChannel('com.example.push_handler');
    _pushChannel.setMethodCallHandler((MethodCall call) async {
      if (call.method == 'receivePushData') {
        Map<String, dynamic> pushData = Map<String, dynamic>.from(call.arguments as Map);
        print('原生传递的推送数据: $pushData');
        // 这里添加Flutter端的消息处理逻辑
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: Scaffold(body: Center(child: Text('Push Demo'))));
  }
}

关键注意事项

  • 必须使用真实iOS设备测试,模拟器无法接收APNs推送。
  • 确保APNs证书和FCM的GoogleService-Info.plist已正确配置到Xcode项目中。
  • 推送权限必须请求到alert权限,provisional权限在终止状态下不会触发通知展示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 03:47:47