Android Smack XMPP Stanza监听器缺失Stanza属性问题
解决Smack中获取
jabber:x:conference扩展元素的reason属性缺失问题 我之前在Android项目中使用Smack处理XMPP消息时,也遇到过完全一样的问题——默认情况下,Smack不会自动解析jabber:x:conference命名空间下的扩展元素属性,导致我们拿不到reason值。下面是亲测有效的解决步骤:
1. 创建自定义扩展元素类
首先,我们需要定义一个实现ExtensionElement的类,用来封装x元素的属性:
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.XmlEnvironment; public class ConferenceExtension implements ExtensionElement { // 固定的命名空间和元素名 public static final String NAMESPACE = "jabber:x:conference"; public static final String ELEMENT_NAME = "x"; private final String jid; private final String reason; public ConferenceExtension(String jid, String reason) { this.jid = jid; this.reason = reason; } @Override public String getElementName() { return ELEMENT_NAME; } @Override public String getNamespace() { return NAMESPACE; } // 提供获取属性的方法 public String getJid() { return jid; } public String getReason() { return reason; } @Override public String toXML(XmlEnvironment xmlEnvironment) { // 生成XML的方法,可选实现,用于发送时使用 return "<x xmlns='" + NAMESPACE + "' jid='" + jid + "' reason='" + reason + "'/>"; } }
2. 实现自定义扩展解析器
接下来,我们需要写一个解析器,告诉Smack如何解析这个x元素的属性:
import org.jivesoftware.smack.packet.XmlEnvironment; import org.jivesoftware.smack.provider.ExtensionElementProvider; import org.xmlpull.v1.XmlPullParser; public class ConferenceExtensionProvider extends ExtensionElementProvider<ConferenceExtension> { @Override public ConferenceExtension parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) throws Exception { // 直接从解析器中获取属性值 String jid = parser.getAttributeValue("", "jid"); String reason = parser.getAttributeValue("", "reason"); // 跳过元素内部的内容(这里x元素是空的,没有子节点) while (parser.next() != XmlPullParser.END_TAG) { // 无需处理任何子元素 } return new ConferenceExtension(jid, reason); } }
3. 注册解析器到Smack
在初始化XMPP连接之前,一定要把我们的解析器注册到ProviderManager中,这样Smack在解析Stanza时才会识别这个扩展:
import org.jivesoftware.smack.provider.ProviderManager; // 在初始化ConnectionConfiguration之前执行 ProviderManager.addExtensionProvider( ConferenceExtension.ELEMENT_NAME, ConferenceExtension.NAMESPACE, new ConferenceExtensionProvider() );
4. 在StanzaListener中获取属性
现在当你收到Message类型的Stanza时,就可以通过扩展元素拿到reason属性了:
StanzaListener stanzaListener = new StanzaListener() { @Override public void processStanza(Stanza stanza) throws SmackException.NotConnectedException, InterruptedException { if (stanza instanceof Message) { Message message = (Message) stanza; // 获取我们自定义的扩展元素 ConferenceExtension conferenceExt = message.getExtension( ConferenceExtension.ELEMENT_NAME, ConferenceExtension.NAMESPACE ); if (conferenceExt != null) { String reason = conferenceExt.getReason(); String mucJid = conferenceExt.getJid(); // 这里就能正常获取到reason属性了 Log.d("XMPP", "新群聊原因: " + reason + ", MUC JID: " + mucJid); } } } };
为什么会出现这个问题?
Smack默认只内置了一些标准XMPP扩展的解析器(比如MUC的http://jabber.org/protocol/muc),而jabber:x:conference是一个比较旧的扩展规范,不在默认解析范围内,所以需要我们手动实现解析逻辑来获取它的属性。
内容的提问来源于stack exchange,提问作者aizat
相关产品推荐
相关产品推荐

