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
相关产品推荐
相关产品推荐

