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

从ejabberd服务器获取XMPP归档消息时didReceiveMAMMessage未调用求助

解决XMPP MAM didReceiveMAMMessage 未调用的问题

我之前处理过类似的ejabberd + XMPPFramework的MAM归档问题,结合你的代码和回调表现,问题大概率出在请求参数错误或者实例管理不当上,下面给你具体的排查和修复步骤:

1. 修正时间字段的参数错误

你的代码里犯了一个明显的参数错误:把起始时间赋值给了end字段,这会导致你查询的是结束时间在3天前的消息(也就是更早的历史),大概率没有匹配的消息,所以didReceiveMAMMessage不会被触发。

修正代码:

// 计算3天前的时间作为查询起始点
let threeDaysAgo = Date().addingTimeInterval(-3 * 24 * 60 * 60)
let startDateString = threeDaysAgo.xmppDateTimeString
// 可选:如果需要限制到当前时间,添加end字段
let endDateString = Date().xmppDateTimeString

// 正确创建start字段
let startField = XMPPMessageArchiveManagement.field(withVar: "start", type: nil, andValue: startDateString)
fields.append(startField)

// 可选添加end字段
let endField = XMPPMessageArchiveManagement.field(withVar: "end", type: nil, andValue: endDateString)
fields.append(endField)

2. 规范"with"字段的创建方式

你手动创建with字段的方式容易出现格式错误,建议使用XMPPFramework提供的封装方法,确保符合MAM协议格式:

// 替换你手动创建的child字段
let withField = XMPPMessageArchiveManagement.field(withVar: "with", type: nil, andValue: user)
fields.append(withField)

⚠️ 注意:user必须是完整的JID格式(比如user@your-ejabberd-domain.com),不能只传用户名。

3. 复用XMPPMessageArchiveManagement实例

你每次调用getArchieveMessages都新建一个xmppMAM实例,这会导致代理绑定不稳定,甚至可能出现stanza无法被正确解析的情况。建议把xmppMAM作为类的属性复用:

class YourChatManager: NSObject, XMPPMessageArchiveManagementDelegate {
    // 把xmppMAM声明为类属性,避免重复创建
    private let xmppMAM = XMPPMessageArchiveManagement()
    private var xmppStream: XMPPStream?

    override init() {
        super.init()
        // 只在初始化时添加一次代理
        xmppMAM.addDelegate(self, delegateQueue: .main)
    }

    func setup(with stream: XMPPStream) {
        self.xmppStream = stream
        xmppMAM.activate(stream)
    }

    func getArchieveMessages(forUser user: String){ 
        guard let stream = xmppStream, stream.isConnected, stream.isAuthenticated else {
            print("Error: XMPP stream not connected or authenticated")
            return
        }

        let threeDaysAgo = Date().addingTimeInterval(-3 * 24 * 60 * 60)
        let startDateString = threeDaysAgo.xmppDateTimeString
        
        var fields: [XMLElement] = [] 
        
        let startField = XMPPMessageArchiveManagement.field(withVar: "start", type: nil, andValue: startDateString)
        fields.append(startField)
        
        let withField = XMPPMessageArchiveManagement.field(withVar: "with", type: nil, andValue: user)
        fields.append(withField)
        
        let set = XMPPResultSet(max: 20)
        xmppMAM.retrieveMessageArchive(at: nil, withFields: fields, with: set) 
    }

    // 确保代理方法正确实现
    func xmppMessageArchiveManagement(_ xmppMessageArchiveManagement: XMPPMessageArchiveManagement, didReceiveMAMMessage message: XMPPMessage, withGroupID groupID: String?) {
        print("Received archived message: \(message.body ?? "No body")")
        // 在这里处理归档消息
    }

    func xmppMessageArchiveManagement(_ xmppMessageArchiveManagement: XMPPMessageArchiveManagement, didFinishReceivingMessagesWith resultSet: XMPPResultSet?) {
        print("Archive fetch finished: \(resultSet?.xmlString ?? "No result set")")
    }
}

4. 检查ejabberd的MAM配置

如果上述代码修复后还是没有效果,需要确认ejabberd端的配置是否正确:

  • 确保mod_mam模块已启用,在ejabberd.yml中配置:
mod_mam:
  default: always  # 默认开启归档
  store_messages: always  # 存储所有消息
  user_prefs: true
  • 确保当前用户有访问归档的权限,ejabberd默认允许用户访问自己的归档,但如果有自定义ACL,需要确认权限配置。

5. 排查XMPPStream状态

调用getArchieveMessages前,必须确保XMPPStream已经连接并完成认证,否则请求会被ejabberd拒绝,不会返回任何消息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 20:27:51