Android平台下基于XMPP的IM研究(二 MultiUserChat 聊天室)

 一直想写东西,但是上班不能在CSDN上写东西。下班回家又忙着学Iphone开发,唉,两个个字,忒忙。今天就写写Smack的聊天室功能吧。

先上代码:

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())); 



 

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

没有更多推荐了,返回首页