iOS应用首次运行无法接收FCM推送问题排查
iOS集成FCM推送异常排查
问题现象
- App首次运行完成会员注册后无法接收推送通知,第二次启动App后推送可正常送达
- 多次关闭重启App后再完成会员注册,同样无法接收推送,再次关闭重启App后推送恢复正常
- 伴随异常:未收到推送直接进入首页后,后续可收到通知,但点击通知时
didReceive回调不触发;即使多次重启设备,FCM token仅在会员注册时上报一次,暂未定位根因
现有业务流程
FCM token上报服务端流程
- 应用启动
- 将获取到的FCM token存储至UserDefaults
- 向用户申请通知权限,获取用户知情同意
- 进入会员注册流程
- 提交会员注册信息时,将会员信息与本地存储的FCM token一同上报服务端
- 会员注册流程完成
复现场景
- 首次运行App并完成会员注册:无法接收推送
- 首次运行完成注册后,关闭应用重新启动:可正常接收推送
- 多次关闭重启App后完成会员注册:无法接收推送
- 多次关闭重启后完成注册,再次关闭重启App:可正常接收推送
现有代码实现
注:用户通知权限申请逻辑位于独立ViewController中,由用户点击按钮触发
AppDelegate FCM核心逻辑
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { FirebaseApp.configure() UNUserNotificationCenter.current().delegate = self Messaging.messaging().delegate = self application.registerForRemoteNotifications() return true } func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { messaging.token { token, _ in guard let token = token else { return } let defaults = UserDefaults.standard defaults.set(token, forKey:"userFCMToken") print("FIR Token : ", token) } }
通知权限申请逻辑
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { success, _ in guard success else { print("用户未同意通知权限") self.registerViewPush() return } print("用户已同意通知权限") self.registerViewPush() }
UNUserNotificationCenterDelegate实现
@available(iOS 10, *) extension AppDelegate: UNUserNotificationCenterDelegate { // App前台运行时接收通知回调 func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { print("willPresent App Push") let userInfo = notification.request.content.userInfo print("============willPresent================") print(userInfo) print("============================") completionHandler([[.alert, .badge, .sound]]) } // 用户点击通知唤起App回调 func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { print("didReceive ") let userInfo = response.notification.request.content.userInfo print("============OriginaldidReceive================") print(userInfo) print("============================") completionHandler() } }
环境信息
- FirebaseMessaging版本:通过CocoaPods安装,版本为9.0.0
- 推送接收成功时的payload示例:
[ AnyHashable("google.c.fid"): f9lzDdLFjkQpneQsfb-GxW, AnyHashable("google.c.sender.id"): 900007830000, AnyHashable("type"): CRING, AnyHashable("aps"): { alert = { body = "message"; title = "message"; }; sound = default; }, AnyHashable("title"): message, AnyHashable("google.c.a.e"): 1, AnyHashable("push"): N, AnyHashable("body"): message, AnyHashable("gcm.message_id"): 1657080600087000 ]
可排查关键点
- Token有效性与时序问题:加日志确认用户同意通知权限前,本地UserDefaults存储的FCM token是否为未绑定APNs权限的临时无效token。当前逻辑是App启动就立刻获取token存本地,用户同意权限后既不重新拉取新token,也不更新本地存储,注册时上报的是无效token自然推送失败;下次App重启时已获得通知权限,FCM才会生成有效token,但因为仅注册时上报一次,服务端仍存储旧token,直到触发上报才会恢复,和现有复现路径完全吻合。
- APNs注册逻辑问题:当前在App刚启动、用户未同意权限时就直接调用
registerForRemoteNotifications(),iOS在用户未授权通知的状态下不会返回有效的APNs device token,FCM拿不到有效APNs token就无法生成可正常下发推送的FCM token。用户同意权限后没有重新调用该方法触发APNs注册流程,必须等下次冷启动才能走通APNs注册、FCM绑定token的全流程。 - Token回调逻辑问题:
messaging(_:didReceiveRegistrationToken:)回调本身已经返回最新的fcmToken,当前实现又额外调用messaging.token异步拉取token,属于冗余逻辑,很容易出现时序问题:比如回调已返回新token,异步拉取时仍拿到旧值存入本地;另外需要加日志确认用户同意通知权限后,该token刷新回调是否会被触发,很多场景下权限状态变更后SDK不会主动触发回调,直到下次启动才会返回新token。 - 通知点击回调不触发问题:当前未实现App杀死状态下冷启动的通知处理逻辑——如果App是被杀死状态,用户点击通知唤起,通知数据存储在
didFinishLaunchingWithOptions的launchOptions参数中,不会走现有实现的didReceive回调;另外需要确认UNUserNotificationCenter.current().delegate = self的设置时机是否晚于回调触发时间点,如果冷启动时代理还未绑定就触发了通知事件,自然无法接收到回调。 - Token上报策略问题:仅在会员注册时上报一次token的逻辑存在缺陷,FCM token并非永久固定,权限变更、APNs token刷新、SDK版本更新、用户重置设备隐私设置都会触发token刷新。正确逻辑应该是每次
didReceiveRegistrationToken回调拿到新token时,先和本地存储的旧token比对,若不一致则更新本地存储,同时判断用户已完成注册的话,立刻将新token上报服务端,而非仅在注册节点上报一次。 - SDK版本问题:FirebaseMessaging 9.0.0属于大版本迭代早期版本,存在数个已知的权限变更后token不刷新、回调不触发的bug,可核对对应版本的已知问题列表,或升级到同大版本的最新稳定小版本验证是否为SDK本身的问题。
内容的提问来源于stack exchange,提问作者KimJitae
相关产品推荐
相关产品推荐

