如何使用XMPP Framework实现接收消息触发本地通知 现有实现不生效如何解决
问题根因
你当前的实现存在以下几个核心问题,导致通知无法每次正常弹出:
- 观察者注册时机错误:仅在
applicationDidEnterBackground中注册通知观察者,若App启动后从未切入后台、或前台运行时收到消息,观察者未被注册,无法响应通知事件;同时未配置观察者移除逻辑,多次切入后台会导致重复注册,同一事件会被多次触发。 - 本地通知ID重复:所有通知使用固定
identifier值localChatNotification,iOS系统会自动覆盖相同ID的未触发通知,短时间收到多条消息时仅会展示最后一条。 - 缺少通知权限申请:未提前向用户申请通知权限,权限被拒绝时所有本地通知都不会弹出。
- 后台网络被挂起:iOS默认App进入后台后约30秒就会暂停所有网络连接,XMPP长连接会被断开,无法收到新消息。
- 线程不匹配:XMPPStream的消息回调默认在后台线程触发,此时操作通知中心接口若未切到主线程,会偶发调用失败。
修复方案
步骤1:提前申请通知权限、注册全局观察者
修改AppDelegate的didFinishLaunchingWithOptions方法,完成权限申请和观察者注册,不再仅在后台时注册:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 申请通知权限 let center = UNUserNotificationCenter.current() center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in if let error = error { print("通知权限申请失败:\(error.localizedDescription)") } } // 全局注册通知观察者 NotificationCenter.default.addObserver(self, selector: #selector(showLocalChatNotification(_:)), name: NSNotification.Name("showLocalNotification"), object: nil) // 原有其他逻辑 return true } // App进入前台时清空角标,可选配置 func applicationWillEnterForeground(_ application: UIApplication) { application.applicationIconBadgeNumber = 0 }
记得删除原来applicationDidEnterBackground中的观察者注册代码。
步骤2:修改通知生成逻辑,修复ID重复、线程问题
@objc private func showLocalChatNotification(_ notification: Notification) { // 仅后台/非活跃状态下弹出通知,前台运行时不需要弹出 guard UIApplication.shared.applicationState != .active else { return } guard let object = notification.object as? [String: String], let name = object["name"], let message = object["message"] else { return } // 切主线程操作通知中心 DispatchQueue.main.async { let content = UNMutableNotificationContent() content.title = name content.body = message content.badge = NSNumber(value: UIApplication.shared.applicationIconBadgeNumber + 1) content.sound = .default // 每次使用唯一ID,避免通知被覆盖,可结合实际消息ID生成 let uniqueIdentifier = "localChatNotification_\(Date().timeIntervalSince1970)" let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false) let request = UNNotificationRequest(identifier: uniqueIdentifier, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) { error in if let error = error { print("Local notification error \(error.localizedDescription)") } } } }
步骤3:配置后台运行权限,保证XMPP长连接后台存活
- 打开Xcode项目,进入
Signing & Capabilities标签页,点击+ Capability添加Background Modes - 勾选
Voice over IP(XMPP长连接后台保活推荐配置)和Remote notifications - 配置XMPPStream的后台保活逻辑,添加如下代码到XMPP初始化的位置:
xmppStream.enableBackgroundingOnSocket = true xmppStream.keepAliveInterval = 30
步骤4:避免重复收到消息
需要在XMPP的消息回调中添加消息去重逻辑,根据消息ID判断是否已经处理过该消息,避免同一消息重复触发通知。
内容的提问来源于stack exchange,提问作者cleanrun
相关产品推荐
相关产品推荐

