iOS集成Firebase推送遇APNS设备令牌未设置错误求助
我正在尝试在iOS中使用Firebase启用推送通知,已完成相关文档的步骤4。目前能获取到FCM Token,但控制台出现以下错误:
APNS device token not set before retrieving FCM Token for Sender ID 'XXXXXXXXX'. Notifications to this FCM Token will not be delivered over APNS.Be sure to re-retrieve the FCM token once the APNS device token is set.
以下是我的代码文件:
PushNotificationManager.swift
import Foundation import FirebaseFirestore import FirebaseMessaging import UIKit import UserNotifications import FirebaseCore class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate { let userID: String init(userID: String) { self.userID = userID super.init() } func registerForPushNotifications() { if #available(iOS 10.0, *) { // For iOS 10 display notification (sent via APNS) UNUserNotificationCenter.current().delegate = self let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization( options: authOptions, completionHandler: {_, _ in }) // For iOS 10 data message (sent via FCM) Messaging.messaging().delegate = self } else { let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil) UIApplication.shared.registerUserNotificationSettings(settings) } UIApplication.shared.registerForRemoteNotifications() updateFirestorePushTokenIfNeeded() } func updateFirestorePushTokenIfNeeded() { if let token = Messaging.messaging().fcmToken { let usersRef = Firestore.firestore().collection("users_table").document(userID) usersRef.setData(["fcmToken": token], merge: true) print(token) } } // func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) { // print(remoteMessage.appData) // } func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { updateFirestorePushTokenIfNeeded() } func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { print(response) } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { print("Registered for Apple Remote Notifications") Messaging.messaging().setAPNSToken(deviceToken, type: .unknown) } }
AppDelegate.swift
import UIKit import FirebaseCore import FirebaseAuth import FirebaseFirestore import FirebaseMessaging @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { FirebaseApp.configure() let db = Firestore.firestore() let pushManager = PushNotificationManager(userID: "currently_logged_in_user_id") pushManager.registerForPushNotifications() if #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate } application.registerForRemoteNotifications() return true } // MARK: UISceneSession Lifecycle func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } }
我尝试了相关解决方案仍未解决,请问可能遗漏了什么?
1. 修复APNS Token回调的归属问题
application(_:didRegisterForRemoteNotificationsWithDeviceToken:)是UIApplicationDelegate的专属回调,你把它放在PushNotificationManager里不会被触发,导致APNS Token无法传递给FCM。
修改步骤:
- 将
PushNotificationManager中的该方法移至AppDelegate - 明确设置APNS Token类型(根据环境选
.sandbox或.prod,不要用.unknown)
修改后的AppDelegate代码片段:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { print("Registered for Apple Remote Notifications") // 根据环境切换Token类型 let tokenType: MessagingAPNSTokenType = AppDelegate.isDebug ? .sandbox : .prod Messaging.messaging().setAPNSToken(deviceToken, type: tokenType) } // 新增环境判断属性 static var isDebug: Bool { #if DEBUG return true #else return false #endif }
2. 避免过早更新FCM Token
你在registerForPushNotifications中直接调用updateFirestorePushTokenIfNeeded(),此时APNS Token尚未获取,生成的FCM Token未关联APNS,属于无效Token。
修改步骤:
移除PushNotificationManager中registerForPushNotifications方法末尾的updateFirestorePushTokenIfNeeded()调用,仅保留messaging(_:didReceiveRegistrationToken:)回调中的更新逻辑——这个回调会在APNS Token设置完成后,自动生成有效的关联Token并触发更新。
3. 修复代理冲突问题
你在AppDelegate中尝试将UNUserNotificationCenter的代理设置为自身,但AppDelegate并未遵守UNUserNotificationCenterDelegate协议,且已在PushNotificationManager中设置过代理,这会导致代理被覆盖,回调失效。
修改步骤:
删除AppDelegate中的以下代码:
if #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate }
4. 确保PushNotificationManager是全局实例
你在didFinishLaunchingWithOptions中创建的pushManager是局部变量,方法执行完毕后会被释放,导致后续的Messaging和Notification回调无法触发。
修改步骤:
在AppDelegate中声明全局变量存储PushNotificationManager实例:
@main class AppDelegate: UIResponder, UIApplicationDelegate { var pushManager: PushNotificationManager? // 全局变量 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { FirebaseApp.configure() let db = Firestore.firestore() pushManager = PushNotificationManager(userID: "currently_logged_in_user_id") pushManager?.registerForPushNotifications() application.registerForRemoteNotifications() return true } // ... 其他代码 }
5. 排查APNS注册失败问题
新增APNS注册失败的回调,确认是否存在权限或配置问题:
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print("APNS注册失败: \(error.localizedDescription)") }
完成以上修改后,重新运行App,FCM会在APNS Token设置完成后生成有效的关联Token,错误提示将消失,推送可正常通过APNS送达。
内容的提问来源于stack exchange,提问作者shivam nanda

