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

Smack开发问题:已连接用户在第三方XMPP客户端始终显示离线

问题分析与解决方案

你遇到的这个问题其实是XMPP协议中Presence(在线状态)传递机制的典型场景——虽然你的Android客户端已经成功发送了available状态的Presence,服务器也识别到你在线,但Gajim/PSI这类客户端不会收到你的状态更新,核心原因是缺少Roster(联系人列表)的订阅关系。

为什么消息能正常交互,但状态不显示?

XMPP协议里,消息(Message)和Presence是两个独立的模块:

  • 消息发送不需要双方在彼此的联系人列表里,只要知道对方的JID就能直接发送,这也是你能正常收发消息的原因;
  • 但Presence的广播是基于Roster订阅关系的——只有当你把对方添加到联系人列表,并且双方完成了订阅(subscribe/subscribed)的双向确认后,服务器才会把你的在线状态推送给对方,反之亦然。ejabberd管理界面显示在线,只是服务器层面记录了你的连接状态,并没有把这个状态主动推送给未订阅的用户。

解决步骤(Smack实现)

你需要在Android客户端中完成「添加联系人+发送订阅请求」的操作,具体代码示例如下:

  1. 获取Roster实例
Roster roster = Roster.getInstanceFor(mConnection);
// 可选:设置自动接受订阅请求,减少手动操作
roster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
  1. 添加Gajim/PSI用户到Roster并发送订阅请求
try {
    // 替换成你的Gajim/PSI用户的完整JID(比如gajim_user@your_ejabberd_domain)
    Jid contactJid = JidCreate.from("gajim_user@your_domain");
    // 创建联系人条目,参数分别是JID、备注、分组(可传null)
    roster.createEntry(contactJid, "Gajim Test User", null);
    
    // 发送订阅请求,告知对方你希望接收他的状态,同时请求他接收你的状态
    Presence subscribePresence = new Presence(Presence.Type.subscribe);
    subscribePresence.setTo(contactJid);
    mConnection.sendStanza(subscribePresence);
} catch (XmppStringprepException | SmackException.NotConnectedException | InterruptedException e) {
    e.printStackTrace();
}
  1. 处理对方的订阅确认
    当Gajim/PSI用户接受你的订阅请求后,你的客户端会收到Presence.Type.subscribed的 stanza,此时双方的订阅关系就建立完成了,之后你和对方就能互相看到在线状态。

额外检查点

  • 优化Presence的显示:你已经设置了available和status,可以额外添加show状态让显示更明确,比如:
Presence stanza = new Presence(Presence.Type.available);
stanza.setStatus("online");
stanza.setShow(Presence.Show.chat); // 设置为"聊天中"状态
this.mConnection.sendStanza(stanza);
  • 确认ejabberd的Roster相关配置没有限制订阅请求(默认配置一般是允许的)。

完成以上操作后,Gajim/PSI应该就能正常显示你的Android客户端的在线状态了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:36:39