android asmack 注册 登陆 聊天 多人聊天室 文件传输

XMPP协议简介

XMPP协议(Extensible Messaging and PresenceProtocol,可扩展消息处理现场协议)是一种基于XML的协议,目的是为了解决及时通信标准而提出来的,最早是在Jabber上实现的。它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。并且XML很易穿过防火墙,所以用XMPP构建的应用不易受到防火墙的阻碍。利用XMPP作为通用的传输机制,不同组织内的不同应用都可以进行有效的通信。

这篇文章有基本的介绍,http://blog.csdn.net/xutaozero21/article/details/4873439 IM

Instant Messenger,及时通信软件,就是大家使用的QQ、MSN Messenger和Gtalk等等。其中Gtalk 就是基于XMPP 协议的一个实现,其他的则不是。当前IM 几乎作为每个上网者必然使用的工具,在国外的大型企业中有一些企业级的IM应用,但是其商业价值还没完全发挥出来。设想既然XMPP 协议是一个公开的协议,那么每个企业都可以利用它来开发适合本身企业工作,提高自身生产效率的IM;甚至,你还可以在网络游戏中集成这种通信软件,不但让你可以边游戏边聊天,也可以开发出适合游戏本身的IM 应用,比如说一些游戏关键场景提醒功能,团队语音交流等等都可以基于IM来实现。

本文主要讲解在android使用xmpp协议进行即时通信,所涉及3个主要的东西,它们是openfire、smack和spark,这个三个东东结合起来就是完整的xmpp IM实现,这里简单介绍一下这3个东东在下文的作用:

openfire主要是作为服务器,负责管理客户端的通信连接,以及提供客户端一些通信信息和连接信息。

Smack主要是xmpp协议的实现,提供了一套很好的api,所以下面操作xmpp都是通过使用smack的api来实现,当然因为是在android里,所以使用的是asmack这个包,里面方法跟smack包差不多。

Spark 是IM客户端的实现,其实就是使用了smack 的api实现的。

下图展示了三者之间的关系:(很明显这个图是偷别人的,具体是哪里我忘了,因为资料都是复制到文档后慢慢研究看的)

从图上可以了解到,client 端和server端都可以通过插件的方式来进行扩展,smack是二者传递数据的媒介。

配置openfire服务器

具体步骤请移步:http://javatech.blog.163.com/blog/static/1766322992010111725339587/

配置成功如果以后ip地址变了,那肯定又是开不了,解决办法请移步:http://blog.csdn.net/HappySheepherder/article/details/4707124

配置成功后,在服务器创建一个简单的用户来测试,然后安装spark,设置好服务器的ip与端口,使用刚才创建的用户登录,登录OK说明服务器成功搭建。

Android IM功能(因为是测试demo,因此界面超级简陋,代码都是给出重要的一部分,剩余的可以在最后下面项目查看)

配置要求

android 2.2、 asmack-jse.jar、myeclipse 连接服务器

在打开软件后会开始初始化,完成与openfire服务器的连接,设置一些配置

[代码]java代码:

static { XMPPConnection.DEBUG_ENABLED = true; final ConnectionConfiguration connectionConfig = new ConnectionConfiguration( host, 5222, ""); // Google talk // ConnectionConfiguration connectionConfig = new // ConnectionConfiguration( // "talk.google.com", 5222, "gmail.com"); // connectionConfig.setSASLAuthenticationEnabled(false); ActivityMain.connection = new XMPPConnection(connectionConfig); ActivityMain.connection.DEBUG_ENABLED = true; ProviderManager pm = ProviderManager.getInstance(); configure(pm); }

注册模块

注册有两种方法:一种是用createAccount ,不过我测试了一下发现不能创建用户,具体原因不详,下面介绍第二种。

如上图:注册成功后服务器将多了ggg用户。

具体实现如下:

[代码]java代码:

Registration reg = new Registration(); reg.setType(IQ.Type.SET); reg.setTo(ConnectionSingleton.getInstance().getServiceName()); reg.setUsername(username.getText().toString()); reg.setPassword(password.getText().toString()); reg.addAttribute("android", "geolo_createUser_android"); System.out.println("reg:" + reg); PacketFilter filter = new AndFilter(new PacketIDFilter(reg .getPacketID()), new PacketTypeFilter(IQ.class)); PacketCollector collector = ConnectionSingleton.getInstance() .createPacketCollector(filter); ConnectionSingleton.getInstance().sendPacket(reg); result = (IQ) collector.nextResult(SmackConfiguration .getPacketReplyTimeout()); // Stop queuing results collector.cancel(); if (result == null) { Toast.makeText(getApplicationContext(), "服, Toast.LENGTH_SHORT).show(); } else if (result.getType() == IQ.Type.ERROR) { if (result.getError().toString().equalsIgnoreCase( "conflict(409)")) { Toast.makeText(getApplicationContext(), "这, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getApplicationContext(), "注, Toast.LENGTH_SHORT).show(); } } else if (result.getType() == IQ.Type.RESULT) { Toast.makeText(getApplicationContext(), "恭, Toast.LENGTH_SHORT).show(); }

使用注册类,设置好注册的用户名密码和一些属性字段,直接设置包过滤,根据这个过滤创建一个结果集合,发送注册信息包,等待获取结果,剩余就是判断结果内容.

登录模块

登录比较简单

[代码]java代码:

ConnectionSingleton.getInstance().connect();// connect String account = etUsername.getText().toString(); String password = etPassword.getText().toString(); // 保存用户和密码ActivityLogin.util.saveString(ACCOUNT_KEY, account); ActivityLogin.util.saveString(PASSWORD_KEY, password); ConnectionSingleton.getInstance().login(account, password);// login // login success System.out.println("login success"); ActivityLogin.mCurrentAccount = account; System.out.println(ConnectionSingleton.getInstance() .getUser()); // 登录成功后发现在线状态Presence presence = new Presence(Presence.Type.available); ConnectionSingleton.getInstance().sendPacket(presence); // 开始主界面Intent intent = new Intent(ActivityLogin.this, ActivityMain.class); startActivity(intent);

获取联系人模块(ActivityMain 主界面)

获取联系人并将相关信息保存到一个list数组里,最后通知listview更新界面

[代码]java代码:

roster = ActivityMain.connection.getRoster();  public void updateRoster() { 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()); User user = new User(); user.setName(entry.getName()); user.setUser(entry.getUser()); user.setType(entry.getType()); user.setSize(entry.getGroups().size()); user.setStatus(presence.getStatus()); user.setFrom(presence.getFrom()); userinfos.add(user); } rosterAdapter.notifyDataSetChanged(); } 

单人聊天模块

第一次修改:

在主界面点击选择一个用户,进入聊天Activity,ActivityChat先获取传过来的用户,创建聊天类并对该用户设置消息监听

[代码]java代码:

ChatManager chatmanager = ConnectionSingleton.getInstance() .getChatManager(); // get user Intent intent = getIntent(); String user = intent.getStringExtra("user"); System.out.println("user:" + user); // new a session newChat = chatmanager.createChat(user, null); // 监听聊天消息 chatmanager.addChatListener(new ChatManagerListenerEx()); // send message try { newChat.sendMessage("im bird man"); } catch (XMPPException e) { // TODO Auto-generated catch block e.printStackTrace(); }

监听类

[代码]java代码:

public class ChatManagerListenerEx implements ChatManagerListener { @Override public void chatCreated(Chat chat, boolean arg1) { // TODO Auto-generated method stub chat.addMessageListener(ml); } } public class MessageListenerEx implements MessageListener { @Override public void processMessage(Chat arg0, Message message) { String result = message.getFrom() + ":" + message.getBody(); System.out.println(result); android.os.Message msg = new android.os.Message(); msg.what = 0; Bundle bd = new Bundle(); bd.putString("msg", result); msg.setData(bd); handler.sendMessage(msg); } }

所获取到的消息都是通过handler来更新UI

[代码]java代码:

public Handler handler = new Handler() { @Override public void handleMessage(android.os.Message msg) { switch (msg.what) { case 0: { String result = msg.getData().getString("msg"); record.setText(record.getText() + "\n" + result); } break; default: break; } } };

aaa跟bbb 的聊天

第二次修改:

第一次的测试,发现如果多个人之间都成为好友,那么他们之间的聊天就出现了接收不到的信息,当然在跟spark测试时,spark可以收到android端的信息,不过android客户端是收到这个信息,不过却没有显示出来,具体原因还不太清楚。因此在第二次修改我改成监听所有聊天信息包,然后再分析包的归属,分发到对应的聊天窗口。

这里就是监听到包后打印的消息,打印出了jid和消息内容

[代码]java代码:

public class XmppMessageManager implements ChatManagerListener { private XMPPConnection _connection; private ChatManager manager = null; public void initialize(XMPPConnection connection) { _connection = connection; manager = _connection.getChatManager(); manager.addChatListener(this); } @Override public void chatCreated(Chat chat, boolean arg1) { // TODO Auto-generated method stub chat.addMessageListener(new MessageListener() { public void processMessage(Chat newchat, Message message) { // 若是聊天窗口存在,将消息转往目前窗口 // 若窗口不存在,创建新的窗口 System.out .println(message.getFrom() + ":" + message.getBody()); if (!ActivityMain.chats.containsKey(message.getFrom())) { ActivityMain.chats.put(message.getFrom(), newchat); } else { } } }); } }

主要就是重写了ChatManagerListener类的监听,分发处理暂时没有想好怎么写。接着在后台启动service就可以开始监听,行了第一次修改那些可以去掉了^0^。

多人聊天模块

也是在主界面的菜单进入ActivityMultiChat,该界面显示所创建的房间,点击就跳转到ActivityMultiRoom 。

获取所有房间比较简单,只需执行下面这段代码

[代码]java代码:

hostrooms = MultiUserChat.getHostedRooms(ActivityMain.connection,

"conference.zhanghaitao-pc");

跳转到后获取要加入的房间的jid,并创建监听。

[代码]java代码:

jid = getIntent().getStringExtra("jid");

  //后面服务名称必需是创建房间的那个服务 String multiUserRoom = jid; try { muc = new MultiUserChat(ActivityMain.connection, multiUserRoom); // 创建聊天室,进入房间后的nickname muc.join(ActivityLogin.mCurrentAccount); Log.v(TAG, "join success"); } catch (XMPPException e) { // TODO Auto-generated catch block e.printStackTrace(); } ChatPacketListener chatListener = new ChatPacketListener(muc); muc.addMessageListener(chatListener);

监听大概的流程跟单人聊天差不多,都是handler来操作。不过多人聊天是重写了PacketListener。具体如下(不过该方法是监听房间的信息,也就是说显示的是以房间为名字的消息):

[代码]java代码:

class ChatPacketListener implements PacketListener { private String _number; private Date _lastDate; private MultiUserChat _muc; private String _roomName; public ChatPacketListener(MultiUserChat muc) { _number = "0"; _lastDate = new Date(0); _muc = muc; _roomName = muc.getRoom(); } @Override public void processPacket(Packet packet) { Message message = (Message) packet; String from = message.getFrom(); if (message.getBody() != null) { DelayInformation inf = (DelayInformation) message.getExtension( "x", "jabber:x:delay"); Date sentDate; if (inf != null) { sentDate = inf.getStamp(); } else { sentDate = new Date(); } Log.w(TAG, "Receive old message: date=" + sentDate.toLocaleString() + " ; message=" + message.getBody()); android.os.Message msg = new android.os.Message(); msg.what = RECEIVE; Bundle bd = new Bundle(); bd.putString("from", from); bd.putString("body", message.getBody()); msg.setData(bd); handler.sendMessage(msg); } } }

下载模块

在主界面对着用户名长按,进入下载activity。进入activityFileTransfer,点击传输按钮即可将文件传输给之前选择的用户,当然这里做得比较简单,并没有拒绝功能,一旦发现有文件就接受。

[代码]java代码:

FileTransferManager transfer = new FileTransferManager( ActivityMain.connection); String destination = user; OutgoingFileTransfer out = transfer .createOutgoingFileTransfer(destination + "/Smack");

那用户是如何监听到有文件并且接受呢?在进入主界面的时候就已经开始了一个service(fileListenerService),该服务创建文件的监听类(XmppFileManager),监听类主要继承FileTransferListener 重写里面的fileTransferRequest方法。

[代码]java代码:

File saveTo; // set answerTo for replies and send() answerTo = request.getRequestor(); if (!Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState())) { send("External Media not mounted read/write"); return; } else if (!landingDir.isDirectory()) { send("The directory " + landingDir.getAbsolutePath() + " is not a directory"); return; } saveTo = new File(landingDir, request.getFileName()); if (saveTo.exists()) { send("The file " + saveTo.getAbsolutePath() + " already exists"); // delete saveTo.delete(); // return; } IncomingFileTransfer transfer = request.accept(); send("File transfer: " + saveTo.getName() + " - " + request.getFileSize() / 1024 + " KB"); try { transfer.recieveFile(saveTo); send("File transfer: " + saveTo.getName() + " - " + transfer.getStatus()); double percents = 0.0; while (!transfer.isDone()) { if (transfer.getStatus().equals(Status.in_progress)) { percents = ((int) (transfer.getProgress() * 10000)) / 100.0; send("File transfer: " + saveTo.getName() + " - " + percents + "%"); } else if (transfer.getStatus().equals(Status.error)) { send(returnAndLogError(transfer)); return; } Thread.sleep(1000); } if (transfer.getStatus().equals(Status.complete)) { send("File transfer complete. File saved as " + saveTo.getAbsolutePath()); } else { send(returnAndLogError(transfer)); } } catch (Exception ex) { String message = "Cannot receive the file because an error occured during the process." + ex; Log.e(TAG, message, ex); send(message); }

网上说文件的传输遇到几个比较重要的问题,我也查看了很多资料(国内的基本是寥寥无几,对此我感到挺无奈的,只能看国外,这样每次我的英语水平都提高了太无奈了^0^)

android asmack 注册 登陆 聊天 多人聊天室 文件传输

时间: 2024-10-22 10:17:23

android asmack 注册 登陆 聊天 多人聊天室 文件传输的相关文章

Android RakNet 系列之四 实现消息、语音、文件传输

简介 RakNet在Win平台上已经实现消息.语音.文件传输了,但在Android平台下尚未实现,笔者决定把源码移植到Android平台下测试. 详情 实现消息 项目自带Chat Example Client和Chat Example Server实现消息,源码简单易懂,此处就不介绍了,直接贴上图片. 测试通过,消息是以Toast方式显示的,图片未捕捉到显示. 实现语音 Win平台下实现语音是通过Portaudio进行的,Portaudio尚未支持Android,要实现语音怎么办? Java层实

Android多人视频聊天应用的开发(三)多人聊天

在上一篇<Android多人视频聊天应用的开发(二)一对一聊天>中我们学习了如何使用声网Agora SDK进行一对一的聊天,本篇主要讨论如何使用Agora SDK进行多人聊天.主要需要实现以下功能: 1.上一篇已经实现过的聊天功能 2.随着加入人数和他们的手机摄像头分辨率的变化,显示不同的UI,即所谓的"分屏" 3.点击分屏中的小窗,可以放大显示该聊天窗 分屏 根据前期技术调研,分屏显示最好的方式是采用瀑布流结合动态聊天窗实现,这样比较方便的能够适应UI的变化.所谓瀑布流,

java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端

java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端 启动界面如下图: 首先启动服务器: 客户端登陆,登陆成功后为: 默认发送是全部用户,是多人发送. 当在边列表里面选择了用户后,可以与此用户建立点对点链接进行聊天,可以发送文件. 用户在线离线状态会实时更新,如果离线,则存为离线消息.当下次上线的时候,会接受到离线消息 从一个用户接受文件的同时,还可以接受从服务器发过来的文件 接受文件完成后,显示记录,并显示保存目录 消息发送演示 服务器端代码: 1 im

基于socket编程的多人聊天室

先是做完的效果图:      server.c 1 /* 服务器端 server.c */ 2 #include <glib.h> 3 #include <stdio.h> 4 #include <fcntl.h> 5 #include <signal.h> 6 #include <sys/socket.h> 7 #include <sys/types.h> 8 #include <sys/time.h> 9 #inclu

nio 代码实现简易多人聊天

这几天在学习nio相关知识.实现了一个简单的多人聊天程序. 服务端代码; 1 import java.io.IOException; 2 import java.net.InetSocketAddress; 3 import java.nio.ByteBuffer; 4 import java.nio.channels.*; 5 import java.nio.charset.Charset; 6 import java.util.*; 7 8 /** 9 * @ClassName CharRo

【原创】android——SQLite实现简单的注册登陆(已经美化)

1,Main_activity的xmL配置 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_pa

【Chat】实验 -- 实现 C/C++下TCP, 服务器/客户端 &quot;多人聊天室&quot;

本次实验利用TCP/IP, 语言环境为 C/C++ 利用套接字Socket编程,以及线程处理, 实现Server/CLient 之间多人的聊天系统的基本功能. 结果大致如: 下面贴上代码(参考参考...) Server 部分: 1 /* TCPdtd.cpp - main, TCPdaytimed */ 2 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <winsock2.h> 6 #include <

基于LBS的多人聊天

基于LBS的多人聊天,布布扣,bubuko.com

找一个陪你聊天的人,很重要

2016-01-08 江徐 经典短篇阅读 作者:江徐丨来源:江徐的自留地(ID:jiangxv08) 有人说,找一个对你知冷知热的人,很重要. 有人说,找一个时刻把你放在第一位的人,很重要. 我要说,找一个与陪你聊天的人,很重要,甚至更重要. 对方既然能够在日日相对夜夜同眠的生活中,与你共绘一幅你爱谈天我爱笑的好景致,又怎么可能对你不是知冷知热.不把你放在重要位置呢? 最近一期金星秀,嘉宾是单眼皮型男赵又廷.从交谈中不难看出,赵又廷是个内敛低调.并非健谈的男人.正是这个坦言自己生活中很宅,而且挺