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

iOS集成Firebase推送遇APNS设备令牌未设置错误求助

iOS Firebase推送通知配置问题

我正在尝试在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:01:14