新安装iOS应用无法接收Firebase推送通知问题
问题现象
Firebase通知配置无误,从Firebase控制台发送的测试通知可正常接收,但后端触发通知时:
- 新安装应用的iOS设备无法接收通知
- 应用终止后执行注销再登录操作,后端通知可正常接收
关键代码与日志分析
iOS端Token注册代码问题
当前在didRegisterForRemoteNotificationsWithDeviceToken中直接同步获取FCM Token:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Messaging.messaging().apnsToken = deviceToken deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)}) fcmTokenString = Messaging.messaging().fcmToken ?? "" // 此处可能尚未生成有效FCM Token UIViewController().deviceToken = deviceTokenString UIViewController().fcmToken = fcmTokenString }
核心问题:FCM Token的生成是异步过程,新安装应用时,didRegisterForRemoteNotificationsWithDeviceToken回调触发时,FCM Token可能还未完成生成,导致存储的是空字符串或无效值。后端使用该无效Token发送通知,自然无法送达设备;而注销再登录时,FCM Token已缓存,此时能获取到有效值。
后端发送日志分析
从日志看,后端调用FCM v1 API返回成功消息:
[2025-01-23 12:26:41] production.ERROR: notification_res-->{
"name": "projects/glo-mini-golf-1dac4/messages/1737635200881686"
}
这说明FCM服务器已接收请求,但如果Token无效,会静默失败(无错误返回,但通知无法送达设备)。
解决方案
1. 正确监听FCM Token生成与更新
实现MessagingDelegate的messaging(_:didReceiveRegistrationToken:)方法,这是FCM官方推荐的获取/更新Token的方式:
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { guard let token = fcmToken, !token.isEmpty else { return } // 存储并上传FCM Token到后端 UserDefaults.standard.set(token, forKey: "fcmToken") // 调用API上传到后端 uploadFCMTokenToBackend(token: token) }
同时在AppDelegate中设置代理:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Messaging.messaging().delegate = self // 其他初始化代码 return true }
2. 确保Token上传时机
仅在获取到有效FCM Token后再上传到后端,避免上传空值或无效值。新安装应用时,等待messaging(_:didReceiveRegistrationToken:)回调触发后再执行上传操作。
3. 验证后端存储的Token
检查新安装用户的fcm_token字段是否为空或无效值,若为空,说明前端未正确上传有效Token,需调整上传逻辑。
4. 补充APNs权限请求
确保应用在启动时正确请求推送权限:
func applicationDidBecomeActive(_ application: UIApplication) { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in if granted { DispatchQueue.main.async { application.registerForRemoteNotifications() } } } }
内容的提问来源于stack exchange,提问作者steveSarsawa

