这篇文章主要介绍如何实现点对点单人聊天、多人的群聊、以及如何给对方发送文件,如何发送图片消息和语音消息等功能。
1.单人聊天
首先创建聊天对象
1 2 3 4 5 6 7 8 9 10 11 12
|
public Chat createChat(String jid) { if(isConnected()) { ChatManager chatManager = ChatManager.getInstanceFor(connection); return chatManager.createChat(jid); } throw new NullPointerException("服务器连接失败,请先连接服务器"); }
|
创建聊天对象时,参数JID记得传聊天JID(解释请参考我的系列文章之基于openfire+smack开发Android即时聊天应用[三]-账号信息、添加好友、JID理解等)给好友发送文本消息
1
| chat.sendMessage(message);
|
2.获取聊天对象管理器
1 2 3 4 5 6 7 8 9 10 11
|
public ChatManager getChatManager() { if(isConnected()) { ChatManager chatManager = ChatManager.getInstanceFor(connection); return chatManager; } throw new NullPointerException("服务器连接失败,请先连接服务器"); }
|
3.接收文本消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private ChatManagerListener chatManagerListener = new ChatManagerListener() { @Override public void chatCreated(Chat chat, boolean createdLocally) { chat.addMessageListener(new ChatMessageListener() { @Override public void processMessage(Chat chat, Message message) { } }); } };
getChatManager().addChatListener(chatManagerListener);
|
上述代码会在你创建聊天对象时对该聊天对象设置消息处理监听,当接收到消息之后,会自动调用processMessage方法进行处理,我们可以在该方法中对接收到的消息进行展示或其他处理,所有好友发送过来的消息都会通过该方法处理。所以该监听最好在登陆之后进行设置,同时在断开连接或是注销时移除该监听。
4.创建群聊聊天室
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
public MultiUserChat createChatRoom(String roomName, String nickName, String password) { if(!isConnected()) { throw new NullPointerException("服务器连接失败,请先连接服务器"); } MultiUserChat muc = null; try { muc = MultiUserChatManager.getInstanceFor(connection).getMultiUserChat(roomName + "@conference." + connection.getServiceName()); boolean isCreated = muc.createOrJoin(nickName); if(isCreated) { Form form = muc.getConfigurationForm(); Form submitForm = form.createAnswerForm(); List fields = form.getFields(); for(int i = 0; fields != null && i < fields.size(); i++) { if(FormField.Type.hidden != fields.get(i).getType() && fields.get(i).getVariable() != null) { submitForm.setDefaultAnswer(fields.get(i).getVariable()); } } List owners = new ArrayList(); owners.add(connection.getUser()); submitForm.setAnswer("muc#roomconfig_roomowners", owners); submitForm.setAnswer("muc#roomconfig_persistentroom", true); submitForm.setAnswer("muc#roomconfig_membersonly", false); submitForm.setAnswer("muc#roomconfig_allowinvites", true); if(password != null && password.length() != 0) { submitForm.setAnswer("muc#roomconfig_passwordprotectedroom", true); submitForm.setAnswer("muc#roomconfig_roomsecret", password); } submitForm.setAnswer("muc#roomconfig_enablelogging", true); submitForm.setAnswer("x-muc#roomconfig_reservednick", true); submitForm.setAnswer("x-muc#roomconfig_canchangenick", false); submitForm.setAnswer("x-muc#roomconfig_registration", false); muc.sendConfigurationForm(submitForm); } } catch (XMPPException | SmackException e) { e.printStackTrace(); return null; } return muc; }
|
上面这段创建群聊聊天室设置表单属性的那段代码引用于网上的代码段。
5.加入群聊聊天室
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
public MultiUserChat joinChatRoom(String roomName, String nickName, String password) { if(!isConnected()) { throw new NullPointerException("服务器连接失败,请先连接服务器"); } try { MultiUserChat muc = MultiUserChatManager.getInstanceFor(connection). getMultiUserChat(roomName + "@conference." + connection.getServiceName()); DiscussionHistory history = new DiscussionHistory(); history.setMaxChars(0); muc.join(nickName, password); return muc; } catch (XMPPException | SmackException e) { e.printStackTrace(); return null; } }
|
在实现加入群聊聊天室的这段代码中有这么一段代码:
1
| getMultiUserChat(roomName + "@conference." + connection.getServiceName());
|
在@与ServiceName中间必须加上conference这个字符串,我也不知道为什么,我最开始时不知道没有加,然后无论如何都加入失败,后来在网上查资料查了半天,有人说是要加上这个,然后我加上就成功了,暂时没搞明白为什么,先把程序跑通会用了再研究其他的原因。
6.群聊发送消息
当你创建或是加入群聊聊天室后,即可获得群聊对象MultiUserChat,通过该对象即可发送群聊消息:
1
| multiUserChat.sendMessage(msg);
|
7.接收群聊消息
1 2 3 4 5 6 7 8 9
| private MessageListener messageListener = new MessageListener() { @Override public void processMessage(Message message) { } };
multiUserChat.addMessageListener(messageListener);
|
群聊接收消息与单聊接收消息还是很像的,只是监听对象,监听方式稍稍有点区别,整个来说,消息接收还是很简单的。
8.获取文件传输对象
1 2 3 4 5 6 7 8 9 10 11 12
|
public OutgoingFileTransfer getSendFileTransfer(String jid) { if(isConnected()) { return FileTransferManager.getInstanceFor(connection).createOutgoingFileTransfer(jid); } throw new NullPointerException("服务器连接失败,请先连接服务器"); }
|
获取文件传输对象时的参数JID记得为文件传输JID:解释请参考我的系列文章之基于openfire+smack开发Android即时聊天应用[三]-账号信息、添加好友、JID理解等
9.发送文件
1 2 3 4 5 6
| OutgoingFileTransfer transfer = getSendFileTransfer(jid);
transfer.sendFile(File file, String description);
以上代码为发送文件file,参数description为对这次文件传输的描述
|
10.文件传输(包括文件发送与接收)过程监听(传输开始、完成、进度百分比)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| if(transfer.getProgress() < 1) {
}
while(!transfer.isDone()) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } }
if(FileTransfer.Status.complete.equals(transfer.getStatus())) { } else if(FileTransfer.Status.cancelled.equals(transfer.getStatus())) { } else if(FileTransfer.Status.error.equals(transfer.getStatus())) { } else if(FileTransfer.Status.refused.equals(transfer.getStatus())) { }
|
以上代码需在子线程执行,可以在文件传输(发送、接收)开始时设置进度条,传输完成时去掉进度条,同时可以通过getProgress()
方法获得文件传输的具体进度百分比。
11.接收文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public void addFileTransferListener(FileTransferListener fileTransferListener) { if(isConnected()) { FileTransferManager.getInstanceFor(connection).addFileTransferListener(fileTransferListener); return; } throw new NullPointerException("服务器连接失败,请先连接服务器"); } addFileTransferListener(new FileTransferListener() { @Override public void fileTransferRequest(FileTransferRequest request) { IncomingFileTransfer transfer = request.accept(); try { String description = request.getDescription(); File file = new File(fileDir ,request.getFileName()); transfer.recieveFile(file); } catch (SmackException | IOException e) { e.printStackTrace(); } } });
|
上面代码为设置文件接收监听
12.发送语音、图片消息
我查看了半天的Smack的API,但是没有找到直接发送语音、图片消息的API,我说说我的实现思路。
其实图片、语音都是文件,我们可以把它们当做文件发送给好友。
在发送文件的同时,用描述字段进行标记传输过来的是图片还是语音。
然后在接收到该文件后通过描述字段进行区分当前接收的是图片文件还是语音文件,然后进行区分展示即可,这样就可以达到发送图片消息和语音消息。
但是我的这种实现方式还是有问题的,因为这种方式对于单聊还是可以实现的。但是如果是群聊的话,我就必须给每个人都发一个相同的文件,这样的话一条语音或图片消息,其实是要发送N次的,对于发送人来说流量就多消耗了N-1倍,所以这种方式对于实现群聊是行不通的。
对于群聊发送语音和图片消息,我的思路是这样的:
- 自己写一个上传文件的服务。
- 发送语音或图片消息时,将图片或语音通过上述上传服务上传到服务器上。
- 在上传完语音或图片后,再向聊天室里发送一个文本消息,发送内容为文件的类似下载地址这样的信息,同时还要告诉群成员这个文件是图片还是语音。
- 群成员接收到这样的特殊文本消息后去自动下载这个文件然后进行展示或是其他处理。
- 群聊天里发送图片或语音消息的这个实现方式我没有验证,但我觉得应该是可行的。至于单聊发送语音或图片消息的思路我是实现验证成功了的,是可行的。
write by laohu
2015-10-30
原创文章,转载请出处注明。
下面是我的个人公众号,欢迎关注交流