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

FCM推送通知无法接收但OneSignal正常,求排查方案及代码审查

解决FCM推送无法接收的问题:配置排查与代码修复

首先,咱们先梳理下可能遗漏的FCM配置点——毕竟OneSignal能正常工作,说明你的APNS基础配置是没问题的,问题大概率出在FCM专属的配置或者代码细节上:

一、排查FCM专属配置遗漏点

  • Firebase控制台APNs证书验证:虽然OneSignal验证过证书,但要确认你在Firebase控制台的iOS应用中上传的APNs证书是否和当前环境匹配(开发环境用开发证书,Ad-hoc/生产用生产证书),并且证书的bundle ID和Xcode项目的bundle ID完全一致。另外,检查GoogleService-Info.plist文件是否正确添加到Xcode项目中,且文件中的BUNDLE_ID、GOOGLE_APP_ID等字段和Firebase控制台的配置匹配。
  • 推送消息类型与环境匹配:FCM推送分「通知消息」和「数据消息」,iOS后台状态下只有通知消息会由APNS直接展示,数据消息需要App处于前台或后台唤醒才能处理。另外,发送推送时要选择正确的环境:开发测试选「开发」,Ad-hoc/正式发布选「生产」,环境不匹配会导致推送无法送达。
  • FCM Token与APNs Token关联:FCM需要关联APNs的device token才能向iOS设备推送,这一步如果没做好,就会直接导致推送失败——这也是你代码里的核心问题之一,咱们后面细说。

二、代码审查与修复建议

我仔细看了你的AppDelegate代码,发现几个关键问题:

1. Firebase初始化时机错误

你在AppDelegate的init()方法中调用FirebaseApp.configure(),这个时机太早了,系统的很多服务还没完成初始化,可能导致Firebase配置不完整。建议把这行代码移到application(_:didFinishLaunchingWithOptions:)方法的最开头:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure() // 移到这里
    // ...其他代码
}

同时删除init()方法中的FirebaseApp.configure()调用。

2. APNs Token关联方法签名错误

你的didRegisterForRemoteNotificationsWithDeviceToken方法签名不符合Swift 3+的规范,导致这个方法不会被系统调用,FCM也就无法获取到APNs的device token——这是推送失败的核心原因!
错误的签名:

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    Messaging.messaging().apnsToken = deviceToken
    print("sdfksjkjfksajkdnslfs")
}

修正后的正确签名(注意参数前的下划线):

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    Messaging.messaging().apnsToken = deviceToken
    print("APNs token registered: \(deviceToken)")
}

3. PushRegistry对象被提前释放

你在didFinishLaunchingWithOptions中创建的PKPushRegistry是局部变量,方法执行完后会被系统释放,导致VoIP推送的delegate无法生效。虽然这和普通FCM推送无关,但还是建议把它改成AppDelegate的属性:

class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, CXProviderDelegate, PKPushRegistryDelegate {
    private var voIPRegistry: PKPushRegistry? // 添加属性
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // ...其他代码
        // PushKit
        voIPRegistry = PKPushRegistry(queue: nil)
        voIPRegistry?.delegate = self
        voIPRegistry?.desiredPushTypes = [PKPushType.voIP]
        // ...其他代码
    }
}

4. 通知授权后的注册优化

在iOS 10+的代码中,建议在用户授权通知后再调用application.registerForRemoteNotifications(),这样更符合系统逻辑,避免用户拒绝授权后仍注册推送:

if #available(iOS 10.0, *) {
    UNUserNotificationCenter.current().delegate = self
    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    UNUserNotificationCenter.current().requestAuthorization(
        options: authOptions, completionHandler: { granted, error in
            if granted {
                DispatchQueue.main.async {
                    application.registerForRemoteNotifications()
                }
            }
        })
} else {
    let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
    application.registerUserNotificationSettings(settings)
    application.registerForRemoteNotifications()
}

同时删除后面单独的application.registerForRemoteNotifications()调用,避免重复注册。

三、额外测试建议

  • 重新获取FCM Token:修改代码后,重启App,查看控制台输出的FCM token是否正常生成,并且确保这个token已经上传到你的服务器(如果需要自己发送推送的话)。
  • 用Firebase控制台发送测试推送:选择正确的环境(开发/生产),输入获取到的FCM Token,发送通知消息,观察App是否能接收。
  • 检查Xcode的Capabilities:确认「Push Notifications」和「Background Modes」(如果需要后台推送处理)已经开启,Background Modes中勾选「Remote notifications」。

内容的提问来源于stack exchange,提问作者Ryoma Kishimoto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:55:04