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

如何使用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长连接后台存活

  1. 打开Xcode项目,进入Signing & Capabilities标签页,点击+ Capability添加Background Modes
  2. 勾选Voice over IP(XMPP长连接后台保活推荐配置)和Remote notifications
  3. 配置XMPPStream的后台保活逻辑,添加如下代码到XMPP初始化的位置:
xmppStream.enableBackgroundingOnSocket = true
xmppStream.keepAliveInterval = 30

步骤4:避免重复收到消息

需要在XMPP的消息回调中添加消息去重逻辑,根据消息ID判断是否已经处理过该消息,避免同一消息重复触发通知。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 02:36:07