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

iOS端Firebase通知异常:后端推送仅控制台显示无弹窗问题

解决iOS FCM后端发送主题通知不弹窗问题

看起来你遇到了FCM推送的常见问题:Firebase控制台发送的通知能正常弹窗,但后端发送的只有日志输出却没有通知提醒。这大概率是后端推送的消息格式不符合APNS要求导致的,下面给你一步步排查和解决的方案:

1. 核心原因:FCM消息类型差异

FCM有两种主要消息类型:

  • Notification消息:由FCM直接传递给APNS,iOS系统会自动处理弹窗、声音和角标,不管App是前台还是后台状态(前台需要额外配置)。Firebase控制台发送的就是这种类型。
  • Data消息:仅作为数据传递给App,系统不会自动展示通知,需要App自己处理展示逻辑。如果你的后端只发送了Data消息,就只会在Xcode控制台看到日志,不会有弹窗。

2. 修复后端推送格式

确保你的后端发送的请求包含notification字段,示例JSON结构如下:

{
  "to": "/topics/notification",
  "notification": {
    "title": "新通知标题",
    "body": "这是通知的内容",
    "sound": "default"
  },
  "data": {
    "custom_key": "自定义数据" // 可选,传递业务数据
  }
}

如果后端之前只发送了data字段,现在加上notification部分就能让系统自动弹窗了。

3. 完善iOS端的通知处理逻辑

结合你提供的代码,还有几个细节需要优化:

(1)调整主题订阅的位置

你现在把主题订阅代码放在didReceiveRemoteNotification里,这会导致每次收到推送才订阅,建议移到didFinishLaunchingWithOptions中,确保App启动时就完成订阅:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // ... 其他初始化代码 ...
    // 移到这里,确保启动时订阅主题
    Messaging.messaging().subscribe(toTopic: "/topics/notification") { error in
        if let error = error {
            print("订阅主题失败: \(error.localizedDescription)")
        } else {
            print("成功订阅notification主题")
        }
    }
    return true
}

(2)实现UNUserNotificationCenterDelegate的关键方法

对于iOS 10+,你已经设置了UNUserNotificationCenter.current().delegate = self,但还需要实现两个关键方法,确保前台和后台都能正确处理通知:

@available(iOS 10.0, *)
extension AppDelegate: UNUserNotificationCenterDelegate {
    // App在前台时收到通知,允许弹窗展示
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // 允许弹窗、声音和角标
        completionHandler([.alert, .sound, .badge])
    }

    // 用户点击通知时触发,处理自定义数据
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        // 这里可以处理通知携带的自定义数据
        print("用户点击了通知,数据:\(userInfo)")
        completionHandler()
    }
}

(3)如果必须使用Data消息的处理方式

如果你的业务场景只能发送Data消息,那需要在App收到消息时手动创建本地通知展示。比如在MessagingDelegate的方法中处理:

extension AppDelegate: MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRemoteMessage remoteMessage: MessagingRemoteMessage) {
        print("收到Data消息: \(remoteMessage.appData)")
        
        // 手动创建本地通知
        let content = UNMutableNotificationContent()
        content.title = remoteMessage.appData["title"] as? String ?? "通知"
        content.body = remoteMessage.appData["body"] as? String ?? "新消息"
        content.sound = .default
        
        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
        UNUserNotificationCenter.current().add(request) { error in
            if let error = error {
                print("创建本地通知失败: \(error.localizedDescription)")
            }
        }
    }
}

4. 额外检查点

  • 确保你的iPhone没有开启专注模式或者通知静音,导致通知被隐藏。
  • 检查App的通知权限是否正常:设置 -> 你的App -> 通知,确认“允许通知”和“横幅样式”已开启。

按照上面的步骤调整后,后端发送的通知应该就能正常弹窗展示了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:34:19