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

SwiftUI中独立推送代理类导致Firebase推送失效的原因

问题:独立RemoteNotificationManager管理Firebase推送代理失效原因

在基于Xcode 15.0.1、测试系统为iOS 16.7的SwiftUI项目中,将Firebase推送的MessagingDelegate与UNUserNotificationCenterDelegate放到独立的RemoteNotificationManager类中管理时,推送功能异常:无法获取deviceToken,Messaging.messaging().apnsToken始终为nil。但将所有推送相关代码移至AppDelegate类中时,推送功能可正常运行。

失效的实现方式

AppDelegate代码:

class AppDelegate: NSObject, UIApplicationDelegate {
    
        let remoteNotificationManager = RemoteNotificationManager()
        func application(
            _ application: UIApplication,
            didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
        ) -> Bool {
            application.registerForRemoteNotifications()
            configureFirebase()
            remoteNotificationManager.configure()
            return true
        }
    }

RemoteNotificationManager代码:

final class RemoteNotificationManager: NSObject {

    func configure() {
        Messaging.messaging().delegate = self
        UNUserNotificationCenter.current().delegate = self
    }
}

// MARK: - Firebase MessagingDelegate

extension RemoteNotificationManager: MessagingDelegate {

    // This fcmToken will be used for device specific notification from Firebase
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        // TODO: Remove print in integration
        if let fcmToken = fcmToken {
            print("RemoteNotificationManager fcm from api: \(fcmToken)")
        }
    }
}

// MARK: - UNUserNotificationCenterDelegate

extension RemoteNotificationManager: UNUserNotificationCenterDelegate {

    func application(
        _ application: UIApplication,
        didFailToRegisterForRemoteNotificationsWithError error: Error
    ) {
        NSLog("Failed to register remote notification. %@", error.localizedDescription)
    }

    func application(
        _ application: UIApplication,
        didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    ) {
        Messaging.messaging().apnsToken = deviceToken
    }

    // This method is called when user taps on a notification
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    ) {
        let userInfo = response.notification.request.content.userInfo
        // TODO: Remove print, integrate
        print("RemoteNotificationManager didReceive: \(userInfo)")
        completionHandler()
    }

    // This method is called when user already in the app and notification arrived
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        // TODO: Remove print, integrate completionHandler
        print("RemoteNotificationManager willPresent: \(notification.request.content.userInfo)")
        completionHandler(.banner)
    }
}

正常工作的实现方式

移至AppDelegate的代码:

class AppDelegate: NSObject, UIApplicationDelegate {

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {
        application.registerForRemoteNotifications()
        configureFirebase()
        configureRemoteNotification()
        return true
    }
}

extension AppDelegate {

    private func configureFirebase() {
        FirebaseApp.configure()
    }

    private func configureRemoteNotification() {
        Messaging.messaging().delegate = self
        UNUserNotificationCenter.current().delegate = self
    }
}

// MARK: - UNUserNotificationCenterDelegate

extension AppDelegate: UNUserNotificationCenterDelegate {

    func application(
        _ application: UIApplication,
        didFailToRegisterForRemoteNotificationsWithError error: Error
    ) {
        NSLog("Failed to register remote notification. %@", error.localizedDescription)
    }

    func application(
        _ application: UIApplication,
        didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    ) {
        Messaging.messaging().apnsToken = deviceToken
    }

    // This method is called when user taps on a notification
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    ) {
        let userInfo = response.notification.request.content.userInfo
        // TODO: Remove print, integrate
        print("RemoteNotificationManager didReceive: \(userInfo)")
        completionHandler()
    }

    // This method is called when user already in the app and notification arrived
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        // TODO: Remove print, integrate completionHandler
        print("RemoteNotificationManager willPresent: \(notification.request.content.userInfo)")
        completionHandler(.banner)
    }
}

// MARK: - Firebase MessagingDelegate

extension AppDelegate: MessagingDelegate {

    // This fcmToken will be used for device specific notification from Firebase
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        // TODO: Remove print in integration
        print("APNS TOKEN \(Messaging.messaging().apnsToken)")
        if let fcmToken = fcmToken {
            print("RemoteNotificationManager fcm from api token: \(fcmToken)")
        }
    }
}

问题原因分析

  • UIApplicationDelegate回调未被触发:你在RemoteNotificationManager中实现的application(_:didRegisterForRemoteNotificationsWithDeviceToken:)和application(_:didFailToRegisterForRemoteNotificationsWithError:)是UIApplicationDelegate协议的方法,系统只会将这些回调发送给已注册的UIApplicationDelegate实例(也就是你的AppDelegate)。RemoteNotificationManager并未实现UIApplicationDelegate协议,也没被系统注册为代理,所以这两个关键方法永远不会被调用,导致你无法将获取到的deviceToken赋值给Messaging.messaging().apnsToken,最终Firebase无法完成与APNs的关联,apnsToken始终为nil。
  • 代理设置仅部分生效:你给Messaging和UNUserNotificationCenter设置RemoteNotificationManager为代理的逻辑是有效的,但缺少deviceToken的关键赋值步骤,Firebase Messaging无法生成有效的FCM Token,整个推送流程断裂。
  • AppDelegate的特殊地位:AppDelegate是系统官方指定的全局代理容器,系统会确保其所有UIApplicationDelegate协议方法被正确调用,所以将回调移到AppDelegate中时,deviceToken能被正常获取并传递给Firebase,推送功能恢复正常。

内容的提问来源于stack exchange,提问作者SM Abu Taher Asif

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:02:08