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

iOS端已终止Flutter App接收静默推送时调用方法的问题

iOS端应用终止时静默推送触发本地通知解决方案

针对你遇到的Flutter应用在iOS终止状态下无法触发静默推送处理逻辑的问题,核心原因是iOS对后台/终止状态下的推送机制有严格限制,且FirebaseMessaging.onBackgroundMessage仅在应用处于后台(未终止)时有效,应用终止时Flutter引擎未启动,无法执行Dart层代码。以下是具体解决步骤:

1. 确保推送Payload格式正确

静默推送必须满足iOS APNs的要求,同时适配Firebase的格式:

  • 必须包含content_available: true(Firebase字段,会自动转换为APNs的content-available: 1)
  • 不能包含alert、sound、badge等触发系统默认通知的字段(否则会被识别为普通通知,而非静默推送)
  • 推送示例(通过Firebase HTTPv1 API发送):
{
  "message": {
    "token": "你的FCM_TOKEN",
    "content_available": true,
    "priority": "high",
    "data": {
      "title": "本地通知标题",
      "body": "本地通知内容",
      "custom_key": "自定义数据"
    }
  }
}

2. 配置iOS后台权限

在Xcode中开启必要的后台模式:

  • 打开项目的Signing & Capabilities标签
  • 添加Background Modes权限,勾选Remote notifications和Background fetch
  • 确保Info.plist中FirebaseAppDelegateProxyEnabled值为YES(默认已配置,若修改过需恢复)

3. 原生层处理应用终止状态的静默推送

应用终止时,Flutter引擎未启动,需在iOS原生代码中处理推送并发送本地通知:
修改AppDelegate.swift:

import UIKit
import Flutter
import Firebase
import UserNotifications

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    FirebaseApp.configure()
    UNUserNotificationCenter.current().delegate = self
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  // 处理终止/后台状态下的静默推送
  override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    // 验证是否为静默推送
    if let contentAvailable = userInfo["content-available"] as? String, contentAvailable == "1" {
      // 从推送data中提取通知内容
      if let data = userInfo["data"] as? [String: Any],
         let title = data["title"] as? String,
         let body = data["body"] as? String {
        // 创建并发送本地通知
        let content = UNMutableNotificationContent()
        content.title = title
        content.body = body
        content.sound = UNNotificationSound.default
        
        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
        UNUserNotificationCenter.current().add(request) { error in
          if let error = error {
            print("本地通知发送失败: \(error.localizedDescription)")
          }
        }
      }
    }
    completionHandler(.newData)
  }
  
  // 前台收到通知时的展示配置(可选)
  override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.alert, .sound, .badge])
  }
}

4. Dart层处理后台(非终止)状态的静默推送

对于应用处于后台(未终止)的情况,使用flutter_local_notifications发送本地通知,配合FirebaseMessaging.onBackgroundMessage:

步骤1:添加依赖

在pubspec.yaml中添加:

dependencies:
  flutter_local_notifications: ^16.1.0

步骤2:初始化本地通知并修改处理逻辑

import 'package:flutter_local_notifications/flutter_local_notifications.dart';

final FlutterLocalNotificationsPlugin _localNotifications = FlutterLocalNotificationsPlugin();

// 初始化本地通知
Future<void> _initLocalNotifications() async {
  const AndroidInitializationSettings androidSettings =
      AndroidInitializationSettings('@mipmap/ic_launcher');
  final DarwinInitializationSettings iosSettings = DarwinInitializationSettings(
    requestAlertPermission: true,
    requestBadgePermission: true,
    requestSoundPermission: true,
  );
  final InitializationSettings settings = InitializationSettings(
    android: androidSettings,
    iOS: iosSettings,
  );
  await _localNotifications.initialize(settings);
}

// 后台消息处理逻辑
Future<void> handleBackgroundMessage(RemoteMessage message) async {
  print("Handling background message: ${message.messageId}");
  
  // 发送本地通知
  const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
    'silent_push_channel',
    '静默推送频道',
    channelDescription: '由静默推送触发的本地通知',
    importance: Importance.max,
    priority: Priority.high,
  );
  const DarwinNotificationDetails iosDetails = DarwinNotificationDetails();
  const NotificationDetails notificationDetails = NotificationDetails(
    android: androidDetails,
    iOS: iosDetails,
  );
  
  await _localNotifications.show(
    0,
    message.data['title'],
    message.data['body'],
    notificationDetails,
    payload: message.data['custom_key'],
  );
}

class FirebaseApi {
  final _firebaseMessaging = FirebaseMessaging.instance;

  Future<String?> initNotifications() async {
    await _firebaseMessaging.requestPermission();

    await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
      alert: true,
      badge: true,
      sound: true,
    );

    // 初始化本地通知
    await _initLocalNotifications();
    
    FirebaseMessaging.onBackgroundMessage(handleBackgroundMessage);

    final fcmToken = await _firebaseMessaging.getToken();
    print('FCM Token: $fcmToken');

    return fcmToken;
  }
}

注意事项

  • iOS静默推送有频率限制,苹果会限制过于频繁的推送请求,避免设备耗电
  • 测试时需先通过Xcode安装应用,手动打开后再终止,再发送推送(直接从Xcode终止应用可能无法触发推送逻辑)
  • 若使用Firebase控制台发送推送,需在「高级选项」中开启「内容可用」,且不要填写通知标题/内容,否则会转为普通通知

内容的提问来源于stack exchange,提问作者B. Bogdan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 11:14:56