从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
相关产品推荐
相关产品推荐

