Android平台下基于XMPP的IM研究

来源:互联网 发布:viove录屏软件 编辑:程序博客网 时间:2024/05/20 21:18

由于项目需要做一个基于XMPP协议的Android通讯软件。故开始研究XMPP

XMPP协议采用的是客户端-服务器架构,所有从一个客户端发到另一个客户端的消息和数据都必须经过XMPP服务器转发,而且支持服务器间DNS的路由,也就是说可以构建服务器集群,使不同的服务器下的客户端也可以通信,XMPP的前身是一个开源组织制定的网络通信协议——Jabber,XMPP的核心是在网络上分片段发送XML流的协议,这个协议是XMPP的即时通讯指令的传递手段。

为了防止服务器间发送的数据被篡改或偷听,XMPP服务器通信引入了TLS机制,使用TLS机制能实现数据的加密,从而保证了在数据传输过程种数据的安全。

一个XMPP实体的地址称为Jabber Identifier或JID,作用类似于IP地址。一个合法的JID包括节点名,域名资源名,其格式为:jid=[node'@']domain['/'resource]

XMPP协议的命名空间:
jabber:iq:private   -- 私有数据存储,用于本地用户私人设置信息,比如用户备注等。
jabber:iq:conference  -- 一般会议,用于多个用户之间的信息共享
jabber:x:encrypted -- 加密的消息,用于发送加密消息
jabber:x:expire  -- 消息终止
jabber:iq:time  -- 客户端时间
jabber:iq:auth  -- 简单用户认证,一般用于服务器之间或者服务器和客户端之间的认证
jabber:x:roster  -- 内部花名册
jabber:x:signed  -- 标记的在线状态
jabber:iq:search -- 用户数据库查询,用于向服务器发送查询请求
jabber:iq:register -- 注册请求,用于用户注册相关信息
jabber:x:iq:roster -- 花名册管理
jabber:x:conference -- 会议邀请,用于向参加会议用户发送开会通知
jabber:x:event  -- 消息事件
vcard-temp  -- 临时的vCard,用于设置用户的头像以及昵称等

 

在网上找了下,有开源的项目BEEM,开源的用于android的xmpp框架asmack,asmack是smack的android版本。现在开始学习smack

。Xmpp就是神马东西,就不废话了。首先在网上下一个Openfire和Spack,不知道这两个是什么东西,就直接google吧。安装openfire需要mysql的支持,当然,Oracle,sqlserver肯定是可以的。还是先上图吧: 

Openfire + Spark + MyXMPPP

 

 

 

  1. import java.io.InputStreamReader;  
  2. import java.util.Collection;  
  3.   
  4. import org.jivesoftware.smack.Chat;  
  5. import org.jivesoftware.smack.ChatManager;  
  6. import org.jivesoftware.smack.ChatManagerListener;  
  7. import org.jivesoftware.smack.ConnectionConfiguration;  
  8. import org.jivesoftware.smack.MessageListener;  
  9. import org.jivesoftware.smack.PrivacyListManager;  
  10. import org.jivesoftware.smack.Roster;  
  11. import org.jivesoftware.smack.RosterEntry;  
  12. import org.jivesoftware.smack.RosterGroup;  
  13. import org.jivesoftware.smack.RosterListener;  
  14. import org.jivesoftware.smack.XMPPConnection;  
  15. import org.jivesoftware.smack.packet.Message;  
  16. import org.jivesoftware.smack.packet.Presence;  
  17.   
  18. public class TestSmack {  
  19.     public static void main(String[] args) {XMPPConnection.DEBUG_ENABLED = true;  
  20.         //我的电脑IP:10.16.25.90  
  21.         final ConnectionConfiguration connectionConfig = new ConnectionConfiguration("10.16.25.91"5222"");  
  22.         connectionConfig.setSASLAuthenticationEnabled(false);  
  23.                 try {  
  24.                       
  25.                     XMPPConnection connection = new XMPPConnection(connectionConfig);  
  26.                     connection.connect();//连接  
  27.                     connection.login("test""test");//登陆  
  28.                     System.out.println(connection.getUser());  
  29.                     ChatManager chatmanager = connection.getChatManager();  
  30.   
  31.                     //新建一个会话  
  32.                     Chat newChat = chatmanager.createChat("test3@pc2010102716"new MessageListener() {  
  33.                         public void processMessage(Chat chat, Message message) {  
  34.                             System.out.println("Received from 【" + message.getFrom() + "】 message: " + message.getBody());  
  35.                         }  
  36.                     });  
  37.                       
  38.                     // 监听被动接收消息,或广播消息监听器  
  39.                     chatmanager.addChatListener(new ChatManagerListener() {  
  40.                         @Override  
  41.                         public void chatCreated(Chat chat, boolean createdLocally) {  
  42.                             chat.addMessageListener(new MessageListener() {  
  43.                                 @Override  
  44.                                 public void processMessage(Chat chat, Message message) {  
  45.                                     System.out.println("Received from 【" + message.getFrom() + "】 message: " + message.getBody());  
  46.                                 }  
  47.                                       
  48.                             });  
  49.                         }  
  50.                     });  
  51.                     //发送消息  
  52.                     newChat.sendMessage("我是菜鸟");  
  53.                       
  54.                     //获取花名册  
  55.                     Roster roster = connection.getRoster();  
  56.                     Collection<RosterEntry> entries = roster.getEntries();  
  57.                     for(RosterEntry entry : entries) {  
  58.                         System.out.print(entry.getName() + " - " + entry.getUser() + " - " + entry.getType() + " - " + entry.getGroups().size());  
  59.                         Presence presence = roster.getPresence(entry.getUser());  
  60.                         System.out.println(" - " + presence.getStatus() +" - "+ presence.getFrom());  
  61.                     }  
  62.                       
  63.                     //添加花名册监听器,监听好友状态的改变。  
  64.                     roster.addRosterListener(new RosterListener() {  
  65.   
  66.                         @Override  
  67.                         public void entriesAdded(Collection<String> addresses) {  
  68.                             System.out.println("entriesAdded");  
  69.                         }  
  70.   
  71.                         @Override  
  72.                         public void entriesUpdated(Collection<String> addresses) {  
  73.                             System.out.println("entriesUpdated");  
  74.                         }  
  75.   
  76.                         @Override  
  77.                         public void entriesDeleted(Collection<String> addresses) {  
  78.                             System.out.println("entriesDeleted");  
  79.                         }  
  80.   
  81.                         @Override  
  82.                         public void presenceChanged(Presence presence) {  
  83.                             System.out.println("presenceChanged - >" + presence.getStatus());  
  84.                         }  
  85.                           
  86.                     });  
  87.                       
  88.                     //创建组  
  89. //                  /RosterGroup group = roster.createGroup("大学");  
  90. //                  for(RosterEntry entry : entries) {  
  91. //                      group.addEntry(entry);  
  92. //                  }  
  93.                     for(RosterGroup g : roster.getGroups()) {  
  94.                         for(RosterEntry entry : g.getEntries()) {  
  95.                             System.out.println("Group " +g.getName() +" >> " + entry.getName() + " - " + entry.getUser() + " - " + entry.getType() + " - " + entry.getGroups().size());  
  96.                         }  
  97.                     }  
  98.                       
  99.                     //发送消息  
  100.                     BufferedReader cmdIn = new BufferedReader(new InputStreamReader(System.in));  
  101.                     while(true) {  
  102.                       try {  
  103.                          String cmd = cmdIn.readLine();  
  104.                          if("!q".equalsIgnoreCase(cmd)) {  
  105.                              break;  
  106.                          }  
  107.                          newChat.sendMessage(cmd);  
  108.                       }catch(Exception ex) {  
  109.                       }  
  110.                     }  
  111.                     connection.disconnect();  
  112.                     System.exit(0);  
  113.                 } catch (Exception e) {  
  114.                     e.printStackTrace();  
  115.                 }  
  116.     }  
  117. }  

以上代码如果在一般的Java Project上运行需要加入smack.jar 和klmx2.jar,如果是Android Project,基本代码不需改变只需将其放入onCreate(...)方法下即可,需要加入asmack.jar包.

1、ConnectionConfiguration
 作为用于与XMPP服务建立连接的配置。它能配置;连接是否使用TLS,SASL加密。
 包含内嵌类:ConnectionConfiguration.SecurityMode

2、XMPPConnection.
 XMPPConnection这个类用来连接XMPP服务.
 可以使用connect()方法建立与服务器的连接。disconnect()方法断开与服务器的连接.
 在创建连接前可以使用XMPPConnection.DEBUG_ENABLED = true; 使开发过程中可以弹出一个GUI窗口,用于显示我们的连接与发送Packet的信息。

3、ChatManager
 用于监控当前所有chat。可以使用createChat(String userJID, MessageListener listener)创建一个聊天。
 
4、Chat
 Chat用于监控两个用户间的一系列message。使用addMessageListener(MessageListener listener)当有任何消息到达时将会触发listener的processMessage(Chat chat, Message message)
方法.
 我们可以使用sendMessage()发送消息,这个方法有两个重载方法,一种类类型的参数时String类型,另一种则是传入Message对象(后面介绍)。
 那么有这样一种情况,当别人主动跟我们建立连接发送消息,或者系统发送消息时我们怎么才能接收消息呢?
    我现在是这样操作的:
 chatmanager.addChatListener(new ChatManagerListener() {
  @Override
  public void chatCreated(Chat chat, boolean createdLocally) {
   chat.addMessageListener(new MessageListener() {
    @Override
    public void processMessage(Chat chat, Message message) {
     System.out.println("Received message: " + message.getBody());
    }
         
   });
  }
 });
 
5、Message
 Message用于表示一个消息包(可以用调试工具看到发送包和接收包的具体内容)。它有以下多种类型。
  Message.Type.NORMAL -- (默认)文本消息(比如邮件)
  Message.Type.CHAT -- 典型的短消息,如QQ聊天的一行一行显示的消息
  Message.Type.GROUP_CHAT -- 群聊消息
  Message.Type.HEADLINE -- 滚动显示的消息
  Message.TYPE.ERROR -- 错误的消息
 Message有两个内部类:
  Message.Body -- 表示消息体
  Message.Type -- 表示消息类型
 
6、Roster
 表示存储了很多RosterEntry的一个花名册.为了易于管理,花名册的项被分贝到了各个group中.
 当建立与XMPP服务的连接后可以使用connection.getRoster()获取Roster对象。
 别的用户可以使用一个订阅请求(相当于QQ加好友)尝试订阅目的用户。可以使用枚举类型Roster.SubscriptionMode的值处理这些请求:
 accept_all: 接收所有订阅请求
 reject_all:拒绝所有订阅请求
 manual:  手工处理订阅请求
 
 创建组:RosterGroup group = roster.createGroup("大学");
 向组中添加RosterEntry对象: group.addEntry(entry);
 
7、RosterEntry
 表示Roster(花名册)中的每条记录.它包含了用户的JID,用户名,或用户分配的昵称.
 
8、RosterGroup
 表示RosterEntry的组。可以使用addEntry(RosterEntry entry)添加。contains(String user) 判断某用户是否在组中.当然removeEntry(RosterEntry entry)就是从组中移除了。getEntries()

获取所有RosterEntry.
 
9、Presence
 表示XMPP状态的packet。每个presence packet都有一个状态。用枚举类型Presence.Type的值表示:
 available -- (默认)用户空闲状态
 unavailable -- 用户没空看消息
 subscribe -- 请求订阅别人,即请求加对方为好友
 subscribed -- 统一被别人订阅,也就是确认被对方加为好友
 unsubscribe -- 他取消订阅别人,请求删除某好友
 unsubscribed -- 拒绝被别人订阅,即拒绝对放的添加请求
 error -- 当前状态packet有错误
 内嵌两个枚举类型:Presence.Mode和Presence.Type.
 可以使用setStatus自定义用户当前的状态(像QQ一样的)


就写写Smack的聊天室功能吧。

先上代码:

  1. import java.io.BufferedReader;   
  2. import java.io.InputStreamReader;   
  3. import java.util.ArrayList;   
  4. import java.util.Collection;   
  5. import java.util.Iterator;   
  6. import java.util.List;   
  7.   
  8. import org.jivesoftware.smack.Chat;   
  9. import org.jivesoftware.smack.ConnectionConfiguration;   
  10. import org.jivesoftware.smack.MessageListener;   
  11. import org.jivesoftware.smack.PacketListener;   
  12. import org.jivesoftware.smack.SmackConfiguration;   
  13. import org.jivesoftware.smack.XMPPConnection;   
  14. import org.jivesoftware.smack.XMPPException;   
  15. import org.jivesoftware.smack.packet.Message;   
  16. import org.jivesoftware.smack.packet.Packet;   
  17. import org.jivesoftware.smack.provider.ProviderManager;   
  18. import org.jivesoftware.smackx.Form;   
  19. import org.jivesoftware.smackx.FormField;   
  20. import org.jivesoftware.smackx.ServiceDiscoveryManager;   
  21. import org.jivesoftware.smackx.muc.DefaultParticipantStatusListener;   
  22. import org.jivesoftware.smackx.muc.DefaultUserStatusListener;   
  23. import org.jivesoftware.smackx.muc.DiscussionHistory;   
  24. import org.jivesoftware.smackx.muc.HostedRoom;   
  25. import org.jivesoftware.smackx.muc.InvitationListener;   
  26. import org.jivesoftware.smackx.muc.InvitationRejectionListener;   
  27. import org.jivesoftware.smackx.muc.MultiUserChat;   
  28. import org.jivesoftware.smackx.muc.RoomInfo;   
  29. import org.jivesoftware.smackx.muc.SubjectUpdatedListener;   
  30. import org.jivesoftware.smackx.packet.ChatStateExtension;   
  31. import org.jivesoftware.smackx.packet.DiscoverInfo;   
  32. import org.jivesoftware.smackx.packet.DiscoverItems;   
  33. import org.jivesoftware.smackx.packet.OfflineMessageInfo;   
  34. import org.jivesoftware.smackx.packet.OfflineMessageRequest;   
  35. import org.jivesoftware.smackx.provider.AdHocCommandDataProvider;   
  36. import org.jivesoftware.smackx.provider.BytestreamsProvider;   
  37. import org.jivesoftware.smackx.provider.DataFormProvider;   
  38. import org.jivesoftware.smackx.provider.DiscoverInfoProvider;   
  39. import org.jivesoftware.smackx.provider.DiscoverItemsProvider;   
  40. import org.jivesoftware.smackx.provider.IBBProviders;   
  41. import org.jivesoftware.smackx.provider.MUCAdminProvider;   
  42. import org.jivesoftware.smackx.provider.MUCOwnerProvider;   
  43. import org.jivesoftware.smackx.provider.MUCUserProvider;   
  44. import org.jivesoftware.smackx.provider.StreamInitiationProvider;   
  45. import org.jivesoftware.smackx.provider.VCardProvider;   
  46. import org.jivesoftware.smackx.provider.XHTMLExtensionProvider;   
  47.   
  48. public class TestSmack2 {   
  49.     public static void main(String[] args) {XMPPConnection.DEBUG_ENABLED = true;   
  50.         final ConnectionConfiguration connectionConfig = new ConnectionConfiguration("PC2010102716"5222"");  
  51.         connectionConfig.setSASLAuthenticationEnabled(false);   
  52.         ProviderManager pm = ProviderManager.getInstance();   
  53.         configure(pm);   
  54.         try {   
  55.             XMPPConnection connection = new XMPPConnection(connectionConfig);   
  56.             connection.connect();//连接   
  57.             initFeatures(connection);   
  58.             connection.login("test""test");//登陆   
  59.             //聊天室   
  60.             //MultiUserChat multiUserChat = new MultiUserChat(connection, new InvitationListener() {});  
  61.              //查找服务   
  62.             System.out.println(connection.getServiceName());   
  63.             List<String> col = getConferenceServices(connection.getServiceName(), connection);  
  64.             for (Object aCol : col) {   
  65.                 String service = (String) aCol;   
  66.                  //查询服务器上的聊天室   
  67.                 Collection<HostedRoom> rooms = MultiUserChat.getHostedRooms(connection, service);  
  68.                 for(HostedRoom room : rooms) {   
  69.                     //查看Room消息   
  70.                     System.out.println(room.getName() + " - " +room.getJid());   
  71.                     RoomInfo roomInfo = MultiUserChat.getRoomInfo(connection, room.getJid());  
  72.                     if(roomInfo != null) {   
  73.                         System.out.println(roomInfo.getOccupantsCount() + " : " + roomInfo.getSubject());  
  74.                     }     
  75.                  }     
  76.             }   
  77.           
  78.             /*---创建默认配置的聊天室 ---  
  79.             先看看官方的文档:  
  80.             Creates a new multi user chat with the specified connection and room name. Note: no 
  81.                   * information is sent to or received from the server until you attempt to  
  82.                  * {@link #join(String) join} the chat room. On some server implementations, 
  83.                   * the room will not be created until the first person joins it  
  84.                  * 最重要一句:直到用户调用join方法的时候聊天室才会被创建  
  85.                  */   
  86.             MultiUserChat muc = new MultiUserChat(connection, "instant@conference.pc2010102716");  
  87.              muc.create("user1");   
  88.             muc.sendConfigurationForm(new Form(Form.TYPE_SUBMIT));   
  89.           
  90.             //----创建手动配置聊天室----   
  91.             muc = new MultiUserChat(connection, "reserved4@conference.pc2010102716");   
  92.           
  93.             //销毁聊天室   
  94.             //muc.destroy("Test", null);   
  95.             muc.create("user2");   
  96.             //获取聊天室的配置表单   
  97.             Form form = muc.getConfigurationForm();   
  98.             //根据原始表单创建一个要提交的新表单   
  99.             Form submitForm = form.createAnswerForm();   
  100.             //向提交的表单添加默认答复   
  101.             for(Iterator<FormField> fields = form.getFields(); fields.hasNext();) {   
  102.                 FormField field = (FormField) fields.next();   
  103.                 if(!FormField.TYPE_HIDDEN.equals(field.getType()) && field.getVariable() != null) {  
  104.                     submitForm.setDefaultAnswer(field.getVariable());   
  105.                 }   
  106.             }   
  107.             //重新设置聊天室名称   
  108.             submitForm.setAnswer("muc#roomconfig_roomname""Reserved4 Room");   
  109.             //设置聊天室的新拥有者   
  110.             List<String> owners = new ArrayList<String>();   
  111.             owners.add("test@pc2010102716");   
  112.             submitForm.setAnswer("muc#roomconfig_roomowners", owners);   
  113.             //设置密码   
  114.             submitForm.setAnswer("muc#roomconfig_passwordprotectedroom"true);   
  115.             submitForm.setAnswer("muc#roomconfig_roomsecret""reserved");   
  116.             //设置描述   
  117.             submitForm.setAnswer("muc#roomconfig_roomdesc""新创建的reserved聊天室");   
  118.             //设置聊天室是持久聊天室,即将要被保存下来   
  119.             //submitForm.setAnswer("muc#roomconfig_persistentroom", true);   
  120.             //发送已完成的表单到服务器配置聊天室   
  121.             muc.sendConfigurationForm(submitForm);   
  122.           
  123.             //加入聊天室(使用昵称喝醉的毛毛虫 ,使用密码ddd)   
  124.             muc = new MultiUserChat(connection, "ddd@conference.pc2010102716");   
  125.             muc.join("喝醉的毛毛虫""ddd");   
  126.           
  127.             //监听消息   
  128.             muc.addMessageListener(new PacketListener() {   
  129.                 @Override   
  130.                 public void processPacket(Packet packet) {   
  131.                     Message message = (Message) packet;   
  132.                     System.out.println(message.getFrom() + " : " + message.getBody());;   
  133.                 }   
  134.             });   
  135.           
  136.             //muc = new MultiUserChat(connection, "ddd@conference.pc2010102716");   
  137.             //muc.join("喝醉的毛毛虫", "ddd");   
  138.           
  139.             //加入聊天室(使用昵称喝醉的毛毛虫 ,使用密码ddd)并且获取聊天室里最后5条信息,   
  140.             //注:addMessageListener监听器必须在此join方法之前,否则无法监听到需要的5条消息   
  141.             muc = new MultiUserChat(connection, "ddd@conference.pc2010102716");   
  142.             DiscussionHistory history = new DiscussionHistory();   
  143.             history.setMaxStanzas(5);   
  144.             muc.join("喝醉的毛毛虫""ddd", history, SmackConfiguration.getPacketReplyTimeout());   
  145.           
  146.             //监听拒绝加入聊天室的用户   
  147.             muc.addInvitationRejectionListener(new InvitationRejectionListener() {   
  148.                 @Override   
  149.                 public void invitationDeclined(String invitee, String reason) {   
  150.                 System.out.println(invitee + " reject invitation, reason is " + reason);   
  151.                 }   
  152.             });   
  153.             //邀请用户加入聊天室   
  154.             muc.invite("test3@pc2010102716""大家来谈谈人生");   
  155.             //监听邀请加入聊天室请求   
  156.             MultiUserChat.addInvitationListener(connection, new InvitationListener() {   
  157.                 @Override   
  158.                 public void invitationReceived(XMPPConnection conn, String room, String inviter, String reason, String password, Message message) {   
  159.                 //例:直接拒绝邀请   
  160.                 MultiUserChat.decline(conn, room, inviter, "你丫很闲啊!");   
  161.                 }   
  162.             });   
  163.           
  164.           
  165.             //根据roomJID获取聊天室信息   
  166.             RoomInfo roomInfo = MultiUserChat.getRoomInfo(connection, "ddd@conference.pc2010102716");  
  167.              System.out.println(roomInfo.getRoom() + "-" + roomInfo.getSubject() + "-" + roomInfo.getOccupantsCount());  
  168.                
  169.             //判断用户是否支持Multi-User聊天协议   
  170.             //注:需要加上资源标识符   
  171.             boolean supports = MultiUserChat.isServiceEnabled(connection, "test3@pc2010102716/spark");  
  172.              //获取某用户所加入的聊天室   
  173.             if(supports) {   
  174.                 Iterator<String> joinedRooms = MultiUserChat.getJoinedRooms(connection, "test3@pc2010102716/spark");  
  175.                 while(joinedRooms.hasNext()) {   
  176.                     System.out.println("test3 has joined Room " + joinedRooms.next());   
  177.                 }   
  178.             }   
  179.           
  180.             //与聊天室用户私聊   
  181.             Chat chat = muc.createPrivateChat("ddd@conference.pc2010102716/飞鸟"new MessageListener() {  
  182.                  @Override   
  183.                  public void processMessage(Chat chat, Message message) {   
  184.                      System.out.println("Private Chat: Received message from " + message.getFrom() + "-" + message.getBody());  
  185.                  }   
  186.             });   
  187.             chat.sendMessage("今天不用加班吧?");   
  188.           
  189.             //改变聊天室主题   
  190.             muc.addSubjectUpdatedListener(new SubjectUpdatedListener() {   
  191.                 @Override   
  192.                 public void subjectUpdated(String subject, String from) {   
  193.                     System.out.println("Subject updated to " + subject +" by " + from);   
  194.                 }   
  195.             });   
  196.             //muc.changeSubject("New Subject11");   
  197.           
  198.             /*一个成员可能有四种角色:  
  199.             1:主持者(Moderator) (权限最大的角色,管理其他成员在聊天室中的角色  
  200.             2:参与者(Participant  
  201.             3:游客 (Visitor) (不能向所有成员发送消息)  
  202.             4:无(没有角色)(NONE)  
  203.             */   
  204.           
  205.             /*聊天室用户可以有5种从属关系  
  206.               * 1、所有者 Owner  
  207.               * 2、管理员 Admin  
  208.               * 3、成员 Member  
  209.               * 4、被驱逐者 Outcast  
  210.               * 5、无(不存在从属关系) None  
  211.               */   
  212.           
  213.             //配置聊天室为Moderated聊天室   
  214.             form = muc.getConfigurationForm();   
  215.             Form answerForm = form.createAnswerForm();   
  216.             answerForm.setAnswer("muc#roomconfig_moderatedroom""1");   
  217.             muc.sendConfigurationForm(answerForm);   
  218.           
  219.             //监听自己的状态变更和事件   
  220.             muc.addUserStatusListener(new DefaultUserStatusListener() {   
  221.                 @Override   
  222.                 public void voiceRevoked() {   
  223.                     super.voiceRevoked();   
  224.                     System.out.println("你被禁言了!");   
  225.                 }   
  226.               
  227.                 @Override   
  228.                 public void voiceGranted() {   
  229.                     super.voiceGranted();   
  230.                     System.out.println("你被批准发言了!");   
  231.                 }   
  232.               
  233.                 @Override   
  234.                 public void membershipGranted() {   
  235.                     super.membershipGranted();   
  236.                     System.out.println("你被赋予了Member权限");   
  237.                 }   
  238.               
  239.                 @Override   
  240.                 public void membershipRevoked() {   
  241.                     super.membershipRevoked();   
  242.                     System.out.println("你被解除了Member权限");   
  243.                 }   
  244.               
  245.                 @Override   
  246.                 public void adminGranted() {   
  247.                     super.adminGranted();   
  248.                     System.out.println("你被赋予了管理员权限");   
  249.                 }   
  250.               
  251.                 @Override   
  252.                 public void adminRevoked() {   
  253.                 super.adminRevoked();   
  254.                 System.out.println("你被解除了管理员权限");   
  255.                 }   
  256.             //......   
  257.             });   
  258.             //房主(Owner)批准test3发言权   
  259.             muc.grantVoice("test3@pc2010102716");   
  260.           
  261.             //监听他人状态变更   
  262.             muc.addParticipantStatusListener(new DefaultParticipantStatusListener() {   
  263.           
  264.                 @Override   
  265.                 public void voiceGranted(String participant) {   
  266.                     super.voiceGranted(participant);   
  267.                 System.out.println(participant + "被批准发言了!");   
  268.                 }   
  269.               
  270.                 @Override   
  271.                 public void voiceRevoked(String participant) {   
  272.                     super.voiceRevoked(participant);   
  273.                     System.out.println(participant + "被禁言了!");   
  274.                 }   
  275.               
  276.                 @Override   
  277.                 public void membershipRevoked(String participant) {   
  278.                     super.membershipRevoked(participant);   
  279.                 }   
  280.               
  281.                 @Override   
  282.                 public void adminGranted(String participant) {   
  283.                     super.adminGranted(participant);   
  284.                 }   
  285.               
  286.                 @Override   
  287.                 public void adminRevoked(String participant) {   
  288.                     super.adminRevoked(participant);   
  289.                 }   
  290.           
  291.             });   
  292.           
  293.             //房主(Owner)批准test3管理员特权   
  294.             muc.grantAdmin("test3@pc2010102716");   
  295.       
  296.       
  297.             //发送消息   
  298.             BufferedReader cmdIn = new BufferedReader(new InputStreamReader(System.in));   
  299.             while(true) {   
  300.                 try {   
  301.                      String cmd = cmdIn.readLine();   
  302.                      if("!q".equalsIgnoreCase(cmd)) {   
  303.                          break;   
  304.                      }   
  305.                   }catch(Exception ex) {   
  306.                   }   
  307.             }   
  308.             connection.disconnect();   
  309.             System.exit(0);         
  310.         } catch (Exception e) {   
  311.             e.printStackTrace();   
  312.         }   
  313.     }   
  314.   
  315.     public static  List<String> getConferenceServices(String server, XMPPConnection connection) throws Exception {  
  316.      List<String> answer = new ArrayList<String>();   
  317.             ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);  
  318.              DiscoverItems items = discoManager.discoverItems(server);   
  319.             for (Iterator<DiscoverItems.Item> it = items.getItems(); it.hasNext();) {  
  320.                  DiscoverItems.Item item = (DiscoverItems.Item)it.next();   
  321.                 if (item.getEntityID().startsWith("conference") || item.getEntityID().startsWith("private")) {  
  322.                      answer.add(item.getEntityID());   
  323.                 }   
  324.                 else {   
  325.                     try {   
  326.                         DiscoverInfo info = discoManager.discoverInfo(item.getEntityID());  
  327.                          if (info.containsFeature("http://jabber.org/protocol/muc")) {  
  328.                              answer.add(item.getEntityID());   
  329.                         }   
  330.                     }   
  331.                     catch (XMPPException e) {   
  332.                     }   
  333.                 }   
  334.             }   
  335.             return answer;   
  336.         }   
  337.   
  338.   
  339.     private static void configure(ProviderManager pm) {   
  340.         // Service Discovery # Items   
  341.         pm.addIQProvider("query""http://jabber.org/protocol/disco#items"new DiscoverItemsProvider());  
  342.          // Service Discovery # Info   
  343.         pm.addIQProvider("query""http://jabber.org/protocol/disco#info"new DiscoverInfoProvider());  
  344.            
  345.         // Service Discovery # Items   
  346.         pm.addIQProvider("query""http://jabber.org/protocol/disco#items"new DiscoverItemsProvider());  
  347.          // Service Discovery # Info   
  348.         pm.addIQProvider("query""http://jabber.org/protocol/disco#info"new DiscoverInfoProvider());  
  349.            
  350.         //Offline Message Requests   
  351.         pm.addIQProvider("offline","http://jabber.org/protocol/offline"new OfflineMessageRequest.Provider());  
  352.                 //Offline Message Indicator   
  353.                 pm.addExtensionProvider("offline","http://jabber.org/protocol/offline"new OfflineMessageInfo.Provider());         
  354.                    
  355.         //vCard   
  356.         pm.addIQProvider("vCard","vcard-temp"new VCardProvider());   
  357.   
  358.         //FileTransfer   
  359.         pm.addIQProvider("si","http://jabber.org/protocol/si"new StreamInitiationProvider());  
  360.                 pm.addIQProvider("query","http://jabber.org/protocol/bytestreams"new BytestreamsProvider());  
  361.                 pm.addIQProvider("open","http://jabber.org/protocol/ibb"new IBBProviders.Open());  
  362.                 pm.addIQProvider("close","http://jabber.org/protocol/ibb"new IBBProviders.Close());  
  363.                 pm.addExtensionProvider("data","http://jabber.org/protocol/ibb"new IBBProviders.Data());          
  364.                 //Data Forms   
  365.             pm.addExtensionProvider("x""jabber:x:data"new DataFormProvider());   
  366.             //Html   
  367.             pm.addExtensionProvider("html""http://jabber.org/protocol/xhtml-im"new XHTMLExtensionProvider());  
  368.             //Ad-Hoc Command   
  369.             pm.addIQProvider("command""http://jabber.org/protocol/commands"new AdHocCommandDataProvider());          
  370.         // Chat State   
  371.         ChatStateExtension.Provider chatState = new ChatStateExtension.Provider();   
  372.         pm.addExtensionProvider("active""http://jabber.org/protocol/chatstates", chatState);  
  373.         pm.addExtensionProvider("composing""http://jabber.org/protocol/chatstates",   
  374.             chatState);   
  375.         pm.addExtensionProvider("paused""http://jabber.org/protocol/chatstates", chatState);  
  376.         pm.addExtensionProvider("inactive""http://jabber.org/protocol/chatstates", chatState);  
  377.         pm.addExtensionProvider("gone""http://jabber.org/protocol/chatstates", chatState);  
  378.         //MUC User,Admin,Owner   
  379.         pm.addExtensionProvider("x""http://jabber.org/protocol/muc#user"new MUCUserProvider());  
  380.         pm.addIQProvider("query""http://jabber.org/protocol/muc#admin"new MUCAdminProvider());  
  381.         pm.addIQProvider("query""http://jabber.org/protocol/muc#owner"new MUCOwnerProvider());  
  382.     }   
  383.   
  384.     private static void initFeatures(XMPPConnection xmppConnection) {   
  385.         ServiceDiscoveryManager.setIdentityName("Android_IM");   
  386.         ServiceDiscoveryManager.setIdentityType("phone");   
  387.         ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(xmppConnection);  
  388.          if(sdm == null) {   
  389.         sdm = new ServiceDiscoveryManager(xmppConnection);   
  390.         }   
  391.         sdm.addFeature("http://jabber.org/protocol/disco#info");   
  392.         sdm.addFeature("http://jabber.org/protocol/caps");   
  393.         sdm.addFeature("urn:xmpp:avatar:metadata");   
  394.         sdm.addFeature("urn:xmpp:avatar:metadata+notify");   
  395.         sdm.addFeature("urn:xmpp:avatar:data");   
  396.         sdm.addFeature("http://jabber.org/protocol/nick");   
  397.         sdm.addFeature("http://jabber.org/protocol/nick+notify");   
  398.         sdm.addFeature("http://jabber.org/protocol/xhtml-im");   
  399.         sdm.addFeature("http://jabber.org/protocol/muc");   
  400.         sdm.addFeature("http://jabber.org/protocol/commands");   
  401.         sdm.addFeature("http://jabber.org/protocol/si/profile/file-transfer");   
  402.         sdm.addFeature("http://jabber.org/protocol/si");   
  403.         sdm.addFeature("http://jabber.org/protocol/bytestreams");   
  404.         sdm.addFeature("http://jabber.org/protocol/ibb");   
  405.         sdm.addFeature("http://jabber.org/protocol/feature-neg");   
  406.         sdm.addFeature("jabber:iq:privacy");   
  407.     }   
  408.   
  409. }  
     

 

上面有两张Spark客户端的聊天室列表占有者一列不同的原因:当使用以下代码获取时不能获取occupantsCount和subject的值:

  1. System.out.println(roomInfo.getOccupantsCount() + " : " + roomInfo.getSubject());  

这是由于Openfire端有个bug(暂且这样说吧,我不知为什么Openfire这样做).首先修改Smack的一个bug,修改RoomInfo类的RoomInfo(DiscoverInfo info) 方法: 

  1. Iterator<String> values = form.getField("muc#roominfo_subject").getValues();  
  2. if (values.hasNext()) {  
  3.     this.subject = values.next();  
  4. }  
  5. else {  
  6.     this.subject = "";  
  7. }    

改为: 

  1. final FormField subjField = form.getField("muc#roominfo_subject");   
  2. this.subject = subjField == null ? "" : subjField.getValues().next();  

修改Openfire的源码,org/jivesoftware/openfire/muc/spi/MultiUserChatServiceImpl类的public DataForm getExtendedInfo(String name, String node, JID senderJID) 方法:

  1.            /*final FormField fieldOcc = dataForm.addField(); */  
  2.            fieldSubj.setVariable("muc#roominfo_occupants");  
  3.            fieldSubj.setLabel(LocaleUtils.getLocalizedString("muc.extended.info.occupants"));  
  4.            fieldSubj.addValue(Integer.toString(room.getOccupantsCount()));  
  5.    

改为: 

  1. final FormField fieldOccu= dataForm.addField();  
  2. fieldOccu.setVariable("muc#roominfo_occupants");  
  3. fieldOccu.setLabel(LocaleUtils.getLocalizedString("muc.extended.info.occupants"));  
  4. fieldOccu.addValue(Integer.toString(room.getOccupantsCount()));   

使用asmack开发基于Android的IM系统同理.


0 0