如何使用订阅模式“both”添加花名册

18

我正在使用 Smack 3.1.0,在添加联系人时,无法获得订阅 "both"。谁能帮助我?以下是我的代码:

Roster.setDefaultSubscriptionMode(Roster.SubscriptionMode.accept_all);
Roster roster = connection.getRoster();
roster.createEntry("buddy@test.com","me",null)

代码执行后,我在Openfire中观察到该订阅为“to”。

5个回答

42
重新编辑@mschonaker的答案,让它更加清晰。两个用户都需要互相订阅并接受他们收到的订阅请求。我们称他们为Alice和Bob。Alice向Bob发送一个订阅请求:
Presence subscribe = new Presence(Presence.Type.subscribe);
subscribe.setTo('bob@example.com');
connection.sendPacket(subscribe);

当 Bob 收到请求后,他会批准它:

Presence subscribed = new Presence(Presence.Type.subscribed);
subscribed.setTo('alice@example.com');
connection.sendPacket(subscribed);

Bob 也可能对 Alice 的存在感到感兴趣,所以他订阅了她:

Presence subscribe = new Presence(Presence.Type.subscribe);
subscribe.setTo('alice@example.com');
connection.sendPacket(subscribe);

同时,Alice 需要批准 Bob 的请求:

Presence subscribed = new Presence(Presence.Type.subscribed);
subscribed.setTo('bob@example.com');
connection.sendPacket(subscribed);

RFC6121第3.1节是目前最好的参考,用于说明这项工作原理。


1
你好。但是在哪里编写这两个代码以订阅双方? - Niranj Patel
为什么Bob在订阅Alice之后又向Alice发送请求...我们能否像Facebook请求那样简单地实现呢?如果Alice向Bob发送请求,Bob将接受它,然后两者成为朋友。@Joe Hildebrand - Roster
@sravani:这就是XMPP的工作方式。你可以在用户界面中隐藏它,许多客户端都这样做。最简单的方法是,如果您从一个联系人那里收到一个“订阅”请求,而花名册订阅状态为“to”,则您的客户端会自动响应“已订阅”。 - Joe Hildebrand
1
很棒的例子@JoeHildebrand,非常感谢您的回答。我想问一个问题,我的情况是当用户A订阅用户B时,当用户B订阅用户A时,自动让用户B订阅用户A,你明白我在说什么吗? - Ali Ashiq
@AliAshiq 我想你在问订阅是否总是双向的。答案大多数情况下是否定的。一些服务器、客户端或库可能会通过自动订阅来响应订阅请求,从而掩盖这一点。 - Joe Hildebrand
显示剩余6条评论

10

双方用户都需要相互订阅,通过发送出席订阅的 stanza。在 Smack 中:

    Presence presence = new Presence(Presence.Type.subscribe);
    presence.setTo(jid);
    connection.sendPacket(presence);

RFC6121的3.1节将为您提供语义细节。


如果用户是从其他来源添加的,则侦听数据包监听器并向JID发送“订阅”以启动工作流程,您会在花名册中看到“both”类型的订阅。如果使用了“订阅”类型,则订阅将来自(被请求方的花名册)和至(请求方所在的花名册)。 - Zoombie
你好。但是在哪里编写这两个代码以订阅双方? - Niranj Patel
RFC3921已被RFC6121所取代。此外,您的代码并不太合理,因为您正在订阅而不是取消订阅,并且“presence”目前不在范围内。 - Joe Hildebrand
优秀的示例,非常感谢您的答案。我还想问一个问题,我的情况是当用户A订阅用户B时,当用户B订阅用户A时,自动订阅用户A,你理解我的意思吗? - Ali Ashiq
我暂时离开XMPP了。你可以在SO上问另一个问题,我想。 - Martín Schonaker
每个请求和每个响应都是单独的、非自动化的操作,需要用户或运行它们的软件明确选择。通常,客户端会自动接受来自你订阅的人的订阅请求。 - Joe Hildebrand

2

好的,我为此努力了几天,最终让事情有了进展。感谢 @Joe Hildebrand 的回答,让我找到了解决问题的正确方向。我已经采用手动订阅模式(即用户需要手动接受另一个用户的请求)来实现它。

如果用户尚未发送订阅或取消订阅请求,服务器会不断地向用户推送订阅请求。因此,您可以将收到的订阅请求保存在本地列表中,并将其显示为“好友请求列表”,以供手动接受/拒绝。如果您的应用程序重新启动(从而重新连接到服务器),服务器将再次推送订阅请求。

它是如何工作的:

  • User1 sends subscribe presence to User2.
  • Roster entry gets automatically created in User1's roster (but not in User2's roster).
  • User2 receives subscribe request from User1.
  • User2 sends back a subscribed presence to User2 (User2 > User1 subscription complete).
  • User2 checks if User1 is in User2's roster. User1 is not in User2's roster. User2 sends back a subscribe presence to User1.
  • Roster entry gets automatically created in User2's roster.
  • User1 receives subscribe presence from User2.
  • User1 checks if User2 is in User1's roster. User2 is in User1's roster. User1 sends back a subscribed presence to User2 (User2 > User1 subscription complete).

            final Presence newPresence = (Presence) packet;
            final Presence.Type presenceType = newPresence.getType();
            final String fromId = newPresence.getFrom();
            final RosterEntry newEntry = getRoster().getEntry(fromId);
    
            if (presenceType == Presence.Type.subscribe)
            {
                //from new user
                if (newEntry == null)
                {
                    //save request locally for later accept/reject
                    //later accept will send back a subscribe & subscribed presence to user with fromId
                    //or accept immediately by sending back subscribe and unsubscribed right now
                }
                //from a user that previously accepted your request
                else
                {
                    //send back subscribed presence to user with fromId
                }
            }
    

1
我曾经遇到同样的问题,但是我找到了解决方法,可以设置为“both”进行订阅。
以下是向用户发送订阅的代码,在添加用户时使用。
 Presence pres = new Presence(Presence.Type.subscribed);
        pres.setPriority(24);
        pres.setMode(Presence.Mode.available);
        pres.setTo(friendJid);

        RoosterConnection.getConnection().sendStanza(pres);

接收端需要将以下方法放在连接类中,而presenceChanged是RosterListener的默认方法。

 @Override
public void presenceChanged(Presence presence) {
    mBus.post(presence);
    try {
        Presence pres = new Presence(Presence.Type.subscribed);
        pres.setTo(presence.getFrom());
        RoosterConnection.getConnection().sendStanza(pres);
    } catch (SmackException.NotConnectedException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

1
如果您正在使用Openfire服务器,您也可以使用用户服务插件,该插件将创建带有订阅的花名册...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接