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

iOS FCM推送问题:APP完全终止时无法捕获自定义数据求助

FCM推送:APP完全终止时点击通知无法获取自定义数据的解决方案

问题核心

APP完全终止(进程被杀)时,点击FCM通知启动APP,UNUserNotificationCenterDelegate或Firebase代理方法未触发,无法读取自定义跳转数据;APP前台/后台运行时点击通知可正常处理。

后端PHP代码分析(你的实现)

<?php
function sendFCMPush($token, $title, $body, $customData) {
    $url = 'https://fcm.googleapis.com/fcm/send';
    $headers = [
        'Authorization: key=YOUR_SERVER_KEY',
        'Content-Type: application/json'
    ];
    
    $payload = [
        'to' => $token,
        'notification' => [
            'title' => $title,
            'body' => $body,
            'sound' => 'default'
        ],
        'data' => $customData // 自定义数据:如['type' => 'order', 'order_id' => '1001']
    ];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    $response = curl_exec($ch);
    curl_close($ch);
    return $response;
}
?>

你的payload结构没问题,data字段会被系统传递到APP,但APP终止时,数据不会直接触发代理方法,而是被封装在启动参数中。

iOS Swift代码修复方案

1. 在didFinishLaunchingWithOptions中处理启动参数

APP终止时点击通知启动,自定义数据会被包含在launchOptions的.remoteNotification键下,必须在这里先处理:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 必须第一时间初始化Firebase并设置代理
    FirebaseApp.configure()
    Messaging.messaging().delegate = self
    UNUserNotificationCenter.current().delegate = self
    
    // 处理终止状态下点击通知启动的场景
    if let remoteNotificationData = launchOptions?[.remoteNotification] as? [AnyHashable: Any] {
        handleCustomNavigation(remoteNotificationData)
    }
    
    // 请求通知权限
    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    UNUserNotificationCenter.current().requestAuthorization(
        options: authOptions,
        completionHandler: { _, _ in })
    application.registerForRemoteNotifications()
    
    return true
}

2. 确保代理方法覆盖所有场景

保留原有代理方法,同时统一处理逻辑:

// 前台收到通知时触发
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    let userInfo = notification.request.content.userInfo
    handleCustomNavigation(userInfo)
    completionHandler([.banner, .sound])
}

// 后台/终止状态点击通知时触发(若代理设置及时)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo
    handleCustomNavigation(userInfo)
    completionHandler()
}

// 接收纯数据消息(无notification字段的推送)
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
    handleCustomNavigation(remoteMessage.appData)
}

// 统一处理跳转逻辑
private func handleCustomNavigation(_ userInfo: [AnyHashable: Any]) {
    guard let type = userInfo["type"] as? String,
          let targetId = userInfo["order_id"] ?? userInfo["product_id"] as? String else {
        return
    }
    
    // 确保在主线程处理UI跳转
    DispatchQueue.main.async {
        guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
              let rootVC = windowScene.windows.first?.rootViewController else {
            return
        }
        
        // 根据type跳转到对应页面
        if type == "order" {
            let orderVC = OrderDetailViewController(orderId: targetId)
            rootVC.show(orderVC, sender: nil)
        } else if type == "product" {
            let productVC = ProductDetailViewController(productId: targetId)
            rootVC.show(productVC, sender: nil)
        }
    }
}

关键注意事项

  • 代理设置时机:必须在didFinishLaunchingWithOptions的最开始设置UNUserNotificationCenter和Messaging的代理,否则系统可能无法找到代理,导致方法不触发。
  • payload验证:确保data字段的键值对是可序列化的JSON类型(字符串、数字、布尔值),避免嵌套复杂对象。
  • 测试方式:测试时必须完全终止APP(Xcode停止运行或多任务栏滑掉),再发送推送点击启动,后台状态的测试不能复现终止场景的问题。
  • iOS版本兼容:iOS 10+必须使用UNUserNotificationCenterDelegate,旧的application:didReceiveRemoteNotification:方法已被废弃。

内容的提问来源于stack exchange,提问作者Kodr.F

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 18:55:29