Firebase Push Notification后台无法正常工作问题求助
解决FCM后台推送无法触发下载和本地通知的问题
我来帮你搞定这个问题,这在iOS开发里是个常见的坑,主要和iOS的推送机制、FCM的消息类型有关,咱们一步步排查:
1. 先搞懂FCM的两种消息类型
iOS后台推送的核心规则要记牢:
- 纯通知消息(只有
notification字段):后台时系统直接帮你弹通知,根本不会走你的自定义代码逻辑,所以下载和本地通知自然触发不了。 - 数据消息/混合消息:只有带
data字段的消息,后台才会把控制权交还给你的APP,让你处理下载和本地通知。- 混合消息(同时有
notification和data):后台时系统会先弹通知,用户点击通知后才会触发你的代码; - 纯数据消息:后台时会直接触发你的推送处理方法(前提是开了后台权限)。
- 混合消息(同时有
2. 必须开启后台推送权限
首先在Info.plist里配置后台模式:
- 添加
UIBackgroundModes数组,把remote-notification加进去。这是APP能在后台接收推送并干活的基础。
3. 正确实现推送回调方法
看你的代码只贴了权限请求的部分,你还需要补充这些关键方法:
针对iOS 10+的UNUserNotificationCenter(推荐用这个)
// 前台收到推送时触发 func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { // 调用你的下载和本地通知逻辑 handlePushContent(notification.request.content.userInfo) // 允许前台展示通知 completionHandler([.alert, .badge, .sound]) } // 后台/未启动时,用户点击通知触发 func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { handlePushContent(response.notification.request.content.userInfo) completionHandler() }
处理纯数据消息的后台回调
如果发的是纯数据消息,后台会直接走这个方法:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { handlePushContent(userInfo) // 告诉系统你处理完了,用.newData表示有新内容 completionHandler(.newData) }
别忘了在didFinishLaunchingWithOptions里补全FCM的配置:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // 请求通知权限 UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.badge,.sound]) { granted, error in if granted { application.registerForRemoteNotifications() } } // 设置FCM和通知中心代理 Messaging.messaging().delegate = self UNUserNotificationCenter.current().delegate = self return true } // 实现FCM代理获取令牌 func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { print("FCM令牌:\(fcmToken ?? "")") // 把令牌发给你的服务器用来推送 }
4. 后台下载要延长运行时间
iOS后台给APP的默认运行时间很短(大概30秒),如果下载耗时久,系统会直接杀进程。你需要用后台任务来续命:
func handlePushContent(_ userInfo: [AnyHashable: Any]) { var backgroundTask: UIBackgroundTaskIdentifier = .invalid // 开始后台任务 backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "PushDownload") { // 超时了,结束任务 UIApplication.shared.endBackgroundTask(backgroundTask) backgroundTask = .invalid } // 模拟下载操作 downloadExtraContent(from: userInfo["content_url"] as? String) { [weak self] in // 下载完成触发本地通知 self?.sendLocalNotification(title: userInfo["title"] as? String ?? "新内容") // 结束后台任务 UIApplication.shared.endBackgroundTask(backgroundTask) backgroundTask = .invalid } }
5. 测试要注意正确姿势
- 别用Xcode调试后台推送!Xcode会让APP保持活跃状态,不算真正的后台。你得把APP退到后台,或者直接断开Xcode在真机上运行。
- 确保服务器端发的消息格式正确,比如纯数据消息的示例:
{ "to": "你的设备FCM令牌", "data": { "content_url": "https://example.com/your-content", "title": "新内容已更新" } }
内容的提问来源于stack exchange,提问作者Rezwan
相关产品推荐
相关产品推荐

