欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中基于XMPP协议实现IM聊天程序与多人聊天室

程序员文章站 2024-02-22 19:32:04
简单的im聊天程序 由于项目需要做一个基于xmpp协议的android通讯软件。故开始研究xmpp。 xmpp协议采用的是客户端-服务器架构,所有从一个客户端发到另一个...

简单的im聊天程序
由于项目需要做一个基于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

Android中基于XMPP协议实现IM聊天程序与多人聊天室

Android中基于XMPP协议实现IM聊天程序与多人聊天室

import java.io.inputstreamreader; 
import java.util.collection; 
 
import org.jivesoftware.smack.chat; 
import org.jivesoftware.smack.chatmanager; 
import org.jivesoftware.smack.chatmanagerlistener; 
import org.jivesoftware.smack.connectionconfiguration; 
import org.jivesoftware.smack.messagelistener; 
import org.jivesoftware.smack.privacylistmanager; 
import org.jivesoftware.smack.roster; 
import org.jivesoftware.smack.rosterentry; 
import org.jivesoftware.smack.rostergroup; 
import org.jivesoftware.smack.rosterlistener; 
import org.jivesoftware.smack.xmppconnection; 
import org.jivesoftware.smack.packet.message; 
import org.jivesoftware.smack.packet.presence; 
 
public class testsmack { 
  public static void main(string[] args) {xmppconnection.debug_enabled = true; 
    //我的电脑ip:10.16.25.90 
    final connectionconfiguration connectionconfig = new connectionconfiguration("10.16.25.91", 5222, ""); 
    connectionconfig.setsaslauthenticationenabled(false); 
        try { 
           
          xmppconnection connection = new xmppconnection(connectionconfig); 
          connection.connect();//连接 
          connection.login("test", "test");//登陆 
          system.out.println(connection.getuser()); 
          chatmanager chatmanager = connection.getchatmanager(); 
 
          //新建一个会话 
          chat newchat = chatmanager.createchat("test3@pc2010102716", new messagelistener() { 
            public void processmessage(chat chat, message message) { 
              system.out.println("received from 【" + message.getfrom() + "】 message: " + message.getbody()); 
            } 
          }); 
           
          // 监听被动接收消息,或广播消息监听器 
          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 from 【" + message.getfrom() + "】 message: " + message.getbody()); 
                } 
                   
              }); 
            } 
          }); 
          //发送消息 
          newchat.sendmessage("我是菜鸟"); 
           
          //获取花名册 
          roster roster = connection.getroster(); 
          collection<rosterentry> entries = roster.getentries(); 
          for(rosterentry entry : entries) { 
            system.out.print(entry.getname() + " - " + entry.getuser() + " - " + entry.gettype() + " - " + entry.getgroups().size()); 
            presence presence = roster.getpresence(entry.getuser()); 
            system.out.println(" - " + presence.getstatus() +" - "+ presence.getfrom()); 
          } 
           
          //添加花名册监听器,监听好友状态的改变。 
          roster.addrosterlistener(new rosterlistener() { 
 
            @override 
            public void entriesadded(collection<string> addresses) { 
              system.out.println("entriesadded"); 
            } 
 
            @override 
            public void entriesupdated(collection<string> addresses) { 
              system.out.println("entriesupdated"); 
            } 
 
            @override 
            public void entriesdeleted(collection<string> addresses) { 
              system.out.println("entriesdeleted"); 
            } 
 
            @override 
            public void presencechanged(presence presence) { 
              system.out.println("presencechanged - >" + presence.getstatus()); 
            } 
             
          }); 
           
          //创建组 
//         /rostergroup group = roster.creategroup("大学"); 
//         for(rosterentry entry : entries) { 
//           group.addentry(entry); 
//         } 
          for(rostergroup g : roster.getgroups()) { 
            for(rosterentry entry : g.getentries()) { 
              system.out.println("group " +g.getname() +" >> " + entry.getname() + " - " + entry.getuser() + " - " + entry.gettype() + " - " + entry.getgroups().size()); 
            } 
          } 
           
          //发送消息 
          bufferedreader cmdin = new bufferedreader(new inputstreamreader(system.in)); 
          while(true) { 
           try { 
             string cmd = cmdin.readline(); 
             if("!q".equalsignorecase(cmd)) { 
               break; 
             } 
             newchat.sendmessage(cmd); 
           }catch(exception ex) { 
           } 
          } 
          connection.disconnect(); 
          system.exit(0); 
        } catch (exception e) { 
          e.printstacktrace(); 
        } 
  } 
} 

以上代码如果在一般的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的信息。

Android中基于XMPP协议实现IM聊天程序与多人聊天室

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一样的)


multiuserchat聊天室

import java.io.bufferedreader;  
import java.io.inputstreamreader;  
import java.util.arraylist;  
import java.util.collection;  
import java.util.iterator;  
import java.util.list;  
 
import org.jivesoftware.smack.chat;  
import org.jivesoftware.smack.connectionconfiguration;  
import org.jivesoftware.smack.messagelistener;  
import org.jivesoftware.smack.packetlistener;  
import org.jivesoftware.smack.smackconfiguration;  
import org.jivesoftware.smack.xmppconnection;  
import org.jivesoftware.smack.xmppexception;  
import org.jivesoftware.smack.packet.message;  
import org.jivesoftware.smack.packet.packet;  
import org.jivesoftware.smack.provider.providermanager;  
import org.jivesoftware.smackx.form;  
import org.jivesoftware.smackx.formfield;  
import org.jivesoftware.smackx.servicediscoverymanager;  
import org.jivesoftware.smackx.muc.defaultparticipantstatuslistener;  
import org.jivesoftware.smackx.muc.defaultuserstatuslistener;  
import org.jivesoftware.smackx.muc.discussionhistory;  
import org.jivesoftware.smackx.muc.hostedroom;  
import org.jivesoftware.smackx.muc.invitationlistener;  
import org.jivesoftware.smackx.muc.invitationrejectionlistener;  
import org.jivesoftware.smackx.muc.multiuserchat;  
import org.jivesoftware.smackx.muc.roominfo;  
import org.jivesoftware.smackx.muc.subjectupdatedlistener;  
import org.jivesoftware.smackx.packet.chatstateextension;  
import org.jivesoftware.smackx.packet.discoverinfo;  
import org.jivesoftware.smackx.packet.discoveritems;  
import org.jivesoftware.smackx.packet.offlinemessageinfo;  
import org.jivesoftware.smackx.packet.offlinemessagerequest;  
import org.jivesoftware.smackx.provider.adhoccommanddataprovider;  
import org.jivesoftware.smackx.provider.bytestreamsprovider;  
import org.jivesoftware.smackx.provider.dataformprovider;  
import org.jivesoftware.smackx.provider.discoverinfoprovider;  
import org.jivesoftware.smackx.provider.discoveritemsprovider;  
import org.jivesoftware.smackx.provider.ibbproviders;  
import org.jivesoftware.smackx.provider.mucadminprovider;  
import org.jivesoftware.smackx.provider.mucownerprovider;  
import org.jivesoftware.smackx.provider.mucuserprovider;  
import org.jivesoftware.smackx.provider.streaminitiationprovider;  
import org.jivesoftware.smackx.provider.vcardprovider;  
import org.jivesoftware.smackx.provider.xhtmlextensionprovider;  
 
public class testsmack2 {  
  public static void main(string[] args) {xmppconnection.debug_enabled = true;  
    final connectionconfiguration connectionconfig = new connectionconfiguration("pc2010102716", 5222, ""); 
    connectionconfig.setsaslauthenticationenabled(false);  
    providermanager pm = providermanager.getinstance();  
    configure(pm);  
    try {  
      xmppconnection connection = new xmppconnection(connectionconfig);  
      connection.connect();//连接  
      initfeatures(connection);  
      connection.login("test", "test");//登陆  
      //聊天室  
      //multiuserchat multiuserchat = new multiuserchat(connection, new invitationlistener() {}); 
       //查找服务  
      system.out.println(connection.getservicename());  
      list<string> col = getconferenceservices(connection.getservicename(), connection); 
      for (object acol : col) {  
        string service = (string) acol;  
         //查询服务器上的聊天室  
        collection<hostedroom> rooms = multiuserchat.gethostedrooms(connection, service); 
        for(hostedroom room : rooms) {  
          //查看room消息  
          system.out.println(room.getname() + " - " +room.getjid());  
          roominfo roominfo = multiuserchat.getroominfo(connection, room.getjid()); 
          if(roominfo != null) {  
            system.out.println(roominfo.getoccupantscount() + " : " + roominfo.getsubject()); 
          }   
         }   
      }  
     
      /*---创建默认配置的聊天室 --- 
      先看看官方的文档: 
      creates a new multi user chat with the specified connection and room name. note: no 
         * information is sent to or received from the server until you attempt to 
         * {@link #join(string) join} the chat room. on some server implementations, 
         * the room will not be created until the first person joins it 
         * 最重要一句:直到用户调用join方法的时候聊天室才会被创建 
         */  
      multiuserchat muc = new multiuserchat(connection, "instant@conference.pc2010102716"); 
       muc.create("user1");  
      muc.sendconfigurationform(new form(form.type_submit));  
     
      //----创建手动配置聊天室----  
      muc = new multiuserchat(connection, "reserved4@conference.pc2010102716");  
     
      //销毁聊天室  
      //muc.destroy("test", null);  
      muc.create("user2");  
      //获取聊天室的配置表单  
      form form = muc.getconfigurationform();  
      //根据原始表单创建一个要提交的新表单  
      form submitform = form.createanswerform();  
      //向提交的表单添加默认答复  
      for(iterator<formfield> fields = form.getfields(); fields.hasnext();) {  
        formfield field = (formfield) fields.next();  
        if(!formfield.type_hidden.equals(field.gettype()) && field.getvariable() != null) { 
          submitform.setdefaultanswer(field.getvariable());  
        }  
      }  
      //重新设置聊天室名称  
      submitform.setanswer("muc#roomconfig_roomname", "reserved4 room");  
      //设置聊天室的新拥有者  
      list<string> owners = new arraylist<string>();  
      owners.add("test@pc2010102716");  
      submitform.setanswer("muc#roomconfig_roomowners", owners);  
      //设置密码  
      submitform.setanswer("muc#roomconfig_passwordprotectedroom", true);  
      submitform.setanswer("muc#roomconfig_roomsecret", "reserved");  
      //设置描述  
      submitform.setanswer("muc#roomconfig_roomdesc", "新创建的reserved聊天室");  
      //设置聊天室是持久聊天室,即将要被保存下来  
      //submitform.setanswer("muc#roomconfig_persistentroom", true);  
      //发送已完成的表单到服务器配置聊天室  
      muc.sendconfigurationform(submitform);  
     
      //加入聊天室(使用昵称喝醉的毛毛虫 ,使用密码ddd)  
      muc = new multiuserchat(connection, "ddd@conference.pc2010102716");  
      muc.join("喝醉的毛毛虫", "ddd");  
     
      //监听消息  
      muc.addmessagelistener(new packetlistener() {  
        @override  
        public void processpacket(packet packet) {  
          message message = (message) packet;  
          system.out.println(message.getfrom() + " : " + message.getbody());;  
        }  
      });  
     
      //muc = new multiuserchat(connection, "ddd@conference.pc2010102716");  
      //muc.join("喝醉的毛毛虫", "ddd");  
     
      //加入聊天室(使用昵称喝醉的毛毛虫 ,使用密码ddd)并且获取聊天室里最后5条信息,  
      //注:addmessagelistener监听器必须在此join方法之前,否则无法监听到需要的5条消息  
      muc = new multiuserchat(connection, "ddd@conference.pc2010102716");  
      discussionhistory history = new discussionhistory();  
      history.setmaxstanzas(5);  
      muc.join("喝醉的毛毛虫", "ddd", history, smackconfiguration.getpacketreplytimeout());  
     
      //监听拒绝加入聊天室的用户  
      muc.addinvitationrejectionlistener(new invitationrejectionlistener() {  
        @override  
        public void invitationdeclined(string invitee, string reason) {  
        system.out.println(invitee + " reject invitation, reason is " + reason);  
        }  
      });  
      //邀请用户加入聊天室  
      muc.invite("test3@pc2010102716", "大家来谈谈人生");  
      //监听邀请加入聊天室请求  
      multiuserchat.addinvitationlistener(connection, new invitationlistener() {  
        @override  
        public void invitationreceived(xmppconnection conn, string room, string inviter, string reason, string password, message message) {  
        //例:直接拒绝邀请  
        multiuserchat.decline(conn, room, inviter, "你丫很闲啊!");  
        }  
      });  
     
     
      //根据roomjid获取聊天室信息  
      roominfo roominfo = multiuserchat.getroominfo(connection, "ddd@conference.pc2010102716"); 
       system.out.println(roominfo.getroom() + "-" + roominfo.getsubject() + "-" + roominfo.getoccupantscount()); 
        
      //判断用户是否支持multi-user聊天协议  
      //注:需要加上资源标识符  
      boolean supports = multiuserchat.isserviceenabled(connection, "test3@pc2010102716/spark"); 
       //获取某用户所加入的聊天室  
      if(supports) {  
        iterator<string> joinedrooms = multiuserchat.getjoinedrooms(connection, "test3@pc2010102716/spark"); 
        while(joinedrooms.hasnext()) {  
          system.out.println("test3 has joined room " + joinedrooms.next());  
        }  
      }  
     
      //与聊天室用户私聊  
      chat chat = muc.createprivatechat("ddd@conference.pc2010102716/飞鸟", new messagelistener() { 
         @override  
         public void processmessage(chat chat, message message) {  
           system.out.println("private chat: received message from " + message.getfrom() + "-" + message.getbody()); 
         }  
      });  
      chat.sendmessage("今天不用加班吧?");  
     
      //改变聊天室主题  
      muc.addsubjectupdatedlistener(new subjectupdatedlistener() {  
        @override  
        public void subjectupdated(string subject, string from) {  
          system.out.println("subject updated to " + subject +" by " + from);  
        }  
      });  
      //muc.changesubject("new subject11");  
     
      /*一个成员可能有四种角色: 
      1:主持者(moderator) (权限最大的角色,管理其他成员在聊天室中的角色 
      2:参与者(participant 
      3:游客 (visitor) (不能向所有成员发送消息) 
      4:无(没有角色)(none) 
      */  
     
      /*聊天室用户可以有5种从属关系 
       * 1、所有者 owner 
       * 2、管理员 admin 
       * 3、成员 member 
       * 4、被驱逐者 outcast 
       * 5、无(不存在从属关系) none 
       */  
     
      //配置聊天室为moderated聊天室  
      form = muc.getconfigurationform();  
      form answerform = form.createanswerform();  
      answerform.setanswer("muc#roomconfig_moderatedroom", "1");  
      muc.sendconfigurationform(answerform);  
     
      //监听自己的状态变更和事件  
      muc.adduserstatuslistener(new defaultuserstatuslistener() {  
        @override  
        public void voicerevoked() {  
          super.voicerevoked();  
          system.out.println("你被禁言了!");  
        }  
       
        @override  
        public void voicegranted() {  
          super.voicegranted();  
          system.out.println("你被批准发言了!");  
        }  
       
        @override  
        public void membershipgranted() {  
          super.membershipgranted();  
          system.out.println("你被赋予了member权限");  
        }  
       
        @override  
        public void membershiprevoked() {  
          super.membershiprevoked();  
          system.out.println("你被解除了member权限");  
        }  
       
        @override  
        public void admingranted() {  
          super.admingranted();  
          system.out.println("你被赋予了管理员权限");  
        }  
       
        @override  
        public void adminrevoked() {  
        super.adminrevoked();  
        system.out.println("你被解除了管理员权限");  
        }  
      //......  
      });  
      //房主(owner)批准test3发言权  
      muc.grantvoice("test3@pc2010102716");  
     
      //监听他人状态变更  
      muc.addparticipantstatuslistener(new defaultparticipantstatuslistener() {  
     
        @override  
        public void voicegranted(string participant) {  
          super.voicegranted(participant);  
        system.out.println(participant + "被批准发言了!");  
        }  
       
        @override  
        public void voicerevoked(string participant) {  
          super.voicerevoked(participant);  
          system.out.println(participant + "被禁言了!");  
        }  
       
        @override  
        public void membershiprevoked(string participant) {  
          super.membershiprevoked(participant);  
        }  
       
        @override  
        public void admingranted(string participant) {  
          super.admingranted(participant);  
        }  
       
        @override  
        public void adminrevoked(string participant) {  
          super.adminrevoked(participant);  
        }  
     
      });  
     
      //房主(owner)批准test3管理员特权  
      muc.grantadmin("test3@pc2010102716");  
   
   
      //发送消息  
      bufferedreader cmdin = new bufferedreader(new inputstreamreader(system.in));  
      while(true) {  
        try {  
           string cmd = cmdin.readline();  
           if("!q".equalsignorecase(cmd)) {  
             break;  
           }  
         }catch(exception ex) {  
         }  
      }  
      connection.disconnect();  
      system.exit(0);     
    } catch (exception e) {  
      e.printstacktrace();  
    }  
  }  
 
  public static list<string> getconferenceservices(string server, xmppconnection connection) throws exception { 
   list<string> answer = new arraylist<string>();  
      servicediscoverymanager discomanager = servicediscoverymanager.getinstancefor(connection); 
       discoveritems items = discomanager.discoveritems(server);  
      for (iterator<discoveritems.item> it = items.getitems(); it.hasnext();) { 
         discoveritems.item item = (discoveritems.item)it.next();  
        if (item.getentityid().startswith("conference") || item.getentityid().startswith("private")) { 
           answer.add(item.getentityid());  
        }  
        else {  
          try {  
            discoverinfo info = discomanager.discoverinfo(item.getentityid()); 
             if (info.containsfeature("http://jabber.org/protocol/muc")) { 
               answer.add(item.getentityid());  
            }  
          }  
          catch (xmppexception e) {  
          }  
        }  
      }  
      return answer;  
    }  
 
 
  private static void configure(providermanager pm) {  
    // service discovery # items  
    pm.addiqprovider("query", "http://jabber.org/protocol/disco#items", new discoveritemsprovider()); 
     // service discovery # info  
    pm.addiqprovider("query", "http://jabber.org/protocol/disco#info", new discoverinfoprovider()); 
      
    // service discovery # items  
    pm.addiqprovider("query", "http://jabber.org/protocol/disco#items", new discoveritemsprovider()); 
     // service discovery # info  
    pm.addiqprovider("query", "http://jabber.org/protocol/disco#info", new discoverinfoprovider()); 
      
    //offline message requests  
    pm.addiqprovider("offline","http://jabber.org/protocol/offline", new offlinemessagerequest.provider()); 
        //offline message indicator  
        pm.addextensionprovider("offline","http://jabber.org/protocol/offline", new offlinemessageinfo.provider());     
          
    //vcard  
    pm.addiqprovider("vcard","vcard-temp", new vcardprovider());  
 
    //filetransfer  
    pm.addiqprovider("si","http://jabber.org/protocol/si", new streaminitiationprovider()); 
        pm.addiqprovider("query","http://jabber.org/protocol/bytestreams", new bytestreamsprovider()); 
        pm.addiqprovider("open","http://jabber.org/protocol/ibb", new ibbproviders.open()); 
        pm.addiqprovider("close","http://jabber.org/protocol/ibb", new ibbproviders.close()); 
        pm.addextensionprovider("data","http://jabber.org/protocol/ibb", new ibbproviders.data());     
        //data forms  
      pm.addextensionprovider("x", "jabber:x:data", new dataformprovider());  
      //html  
      pm.addextensionprovider("html", "http://jabber.org/protocol/xhtml-im", new xhtmlextensionprovider()); 
      //ad-hoc command  
      pm.addiqprovider("command", "http://jabber.org/protocol/commands", new adhoccommanddataprovider());     
    // chat state  
    chatstateextension.provider chatstate = new chatstateextension.provider();  
    pm.addextensionprovider("active", "http://jabber.org/protocol/chatstates", chatstate); 
    pm.addextensionprovider("composing", "http://jabber.org/protocol/chatstates",  
      chatstate);  
    pm.addextensionprovider("paused", "http://jabber.org/protocol/chatstates", chatstate); 
    pm.addextensionprovider("inactive", "http://jabber.org/protocol/chatstates", chatstate); 
    pm.addextensionprovider("gone", "http://jabber.org/protocol/chatstates", chatstate); 
    //muc user,admin,owner  
    pm.addextensionprovider("x", "http://jabber.org/protocol/muc#user", new mucuserprovider()); 
    pm.addiqprovider("query", "http://jabber.org/protocol/muc#admin", new mucadminprovider()); 
    pm.addiqprovider("query", "http://jabber.org/protocol/muc#owner", new mucownerprovider()); 
  }  
 
  private static void initfeatures(xmppconnection xmppconnection) {  
    servicediscoverymanager.setidentityname("android_im");  
    servicediscoverymanager.setidentitytype("phone");  
    servicediscoverymanager sdm = servicediscoverymanager.getinstancefor(xmppconnection); 
     if(sdm == null) {  
    sdm = new servicediscoverymanager(xmppconnection);  
    }  
    sdm.addfeature("http://jabber.org/protocol/disco#info");  
    sdm.addfeature("http://jabber.org/protocol/caps");  
    sdm.addfeature("urn:xmpp:avatar:metadata");  
    sdm.addfeature("urn:xmpp:avatar:metadata+notify");  
    sdm.addfeature("urn:xmpp:avatar:data");  
    sdm.addfeature("http://jabber.org/protocol/nick");  
    sdm.addfeature("http://jabber.org/protocol/nick+notify");  
    sdm.addfeature("http://jabber.org/protocol/xhtml-im");  
    sdm.addfeature("http://jabber.org/protocol/muc");  
    sdm.addfeature("http://jabber.org/protocol/commands");  
    sdm.addfeature("http://jabber.org/protocol/si/profile/file-transfer");  
    sdm.addfeature("http://jabber.org/protocol/si");  
    sdm.addfeature("http://jabber.org/protocol/bytestreams");  
    sdm.addfeature("http://jabber.org/protocol/ibb");  
    sdm.addfeature("http://jabber.org/protocol/feature-neg");  
    sdm.addfeature("jabber:iq:privacy");  
  }  
 
}  

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

system.out.println(roominfo.getoccupantscount() + " : " + roominfo.getsubject()); 

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

iterator<string> values = form.getfield("muc#roominfo_subject").getvalues(); 
if (values.hasnext()) { 
  this.subject = values.next(); 
} 
else { 
  this.subject = ""; 
} 
 

改为:   

final formfield subjfield = form.getfield("muc#roominfo_subject");  
this.subject = subjfield == null ? "" : subjfield.getvalues().next(); 

  修改openfire的源码,org/jivesoftware/openfire/muc/spi/multiuserchatserviceimpl类的public dataform getextendedinfo(string name, string node, jid senderjid) 方法:         

      /*final formfield fieldocc = dataform.addfield(); */ 
      fieldsubj.setvariable("muc#roominfo_occupants"); 
      fieldsubj.setlabel(localeutils.getlocalizedstring("muc.extended.info.occupants")); 
      fieldsubj.addvalue(integer.tostring(room.getoccupantscount())); 

  
改为:         

final formfield fieldoccu= dataform.addfield(); 
fieldoccu.setvariable("muc#roominfo_occupants"); 
fieldoccu.setlabel(localeutils.getlocalizedstring("muc.extended.info.occupants")); 
fieldoccu.addvalue(integer.tostring(room.getoccupantscount()));  

Android中基于XMPP协议实现IM聊天程序与多人聊天室

Android中基于XMPP协议实现IM聊天程序与多人聊天室

Android中基于XMPP协议实现IM聊天程序与多人聊天室

Android中基于XMPP协议实现IM聊天程序与多人聊天室

Android中基于XMPP协议实现IM聊天程序与多人聊天室

Android中基于XMPP协议实现IM聊天程序与多人聊天室

使用asmack开发基于android的im系统同理.