您的位置:首页 > 运维架构

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

2015-05-06 17:29 232 查看
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服务器的连接,设置一些配置

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">static </span><span style="margin: 0px; padding: 0px; color: black;">{
XMPPConnection.</span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">DEBUG_ENABLED </span><span style="margin: 0px; padding: 0px; color: black;">= </span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">true</span><span style="margin: 0px; padding: 0px; color: black;">;
</span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">final </span><span style="margin: 0px; padding: 0px; color: black;">ConnectionConfiguration connectionConfig = </span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span><span style="margin: 0px; padding: 0px; color: black;">ConnectionConfiguration(
</span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">host</span><span style="margin: 0px; padding: 0px; color: black;">, 5222, </span><span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">""</span><span style="margin: 0px; padding: 0px; color: black;">);
</span><span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// Google talk
// ConnectionConfiguration connectionConfig = new
// ConnectionConfiguration(
// "talk.google.com", 5222, "gmail.com");</span><span style="margin: 0px; padding: 0px; color: black;"></span>
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">        // connectionConfig.setSASLAuthenticationEnabled(false);
</span><span style="margin: 0px; padding: 0px; color: black;">ActivityMain.</span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">connection </span><span style="margin: 0px; padding: 0px; color: black;">= </span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span><span style="margin: 0px; padding: 0px; color: black;">XMPPConnection(connectionConfig);

ActivityMain.</span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">connection</span><span style="margin: 0px; padding: 0px; color: black;">.</span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">DEBUG_ENABLED </span><span style="margin: 0px; padding: 0px; color: black;">= </span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">true</span><span style="margin: 0px; padding: 0px; color: black;">;

ProviderManager pm = </span><span style="margin: 0px; padding: 0px; color: blue;">ProviderManager</span><span style="margin: 0px; padding: 0px; color: black;">.getInstance();
configure(pm);
}

</span>


注册模块

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





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

具体实现如下:

Registration reg = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span><span style="margin: 0px; padding: 0px; color: blue;">Registration</span>();
reg.setType(IQ.Type.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">SET</span>);
reg.setTo(ConnectionSingleton.getInstance().getServiceName());
reg.setUsername(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">username</span>.getText().toString());
reg.setPassword(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">password</span>.getText().toString());
reg.addAttribute(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"android"</span>, <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"geolo_createUser_android"</span>);
System.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">out</span>.println(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"reg:" </span>+ reg);
PacketFilter filter = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>AndFilter(<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>PacketIDFilter(reg
.getPacketID()), <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>PacketTypeFilter(IQ.<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">class</span>));
PacketCollector collector = ConnectionSingleton.getInstance()
.createPacketCollector(filter);
ConnectionSingleton.getInstance().sendPacket(reg);

<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">result </span>= (IQ) collector.nextResult(SmackConfiguration
.getPacketReplyTimeout());
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// Stop queuing results
</span>collector.cancel();<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">
</span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">if </span>(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">result </span>== <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">null</span>) {
Toast.makeText(getApplicationContext(), <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"服</span>,
Toast.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">LENGTH_SHORT</span>).show();
} <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">else if </span>(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">result</span>.getType() == IQ.Type.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">ERROR</span>) {
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">if </span>(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">result</span>.getError().toString().equalsIgnoreCase(
<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"conflict(409)"</span>)) {
Toast.makeText(getApplicationContext(), <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"这</span>,
Toast.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">LENGTH_SHORT</span>).show();
} <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">else </span>{
Toast.makeText(getApplicationContext(), <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"注</span>,
Toast.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">LENGTH_SHORT</span>).show();
}
} <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">else if </span>(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">result</span>.getType() == IQ.Type.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">RESULT</span>) {
Toast.makeText(getApplicationContext(), <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"恭</span>,
Toast.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">LENGTH_SHORT</span>).show();
}


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

 


登录模块

登录比较简单

ConnectionSingleton.getInstance().connect();<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// connect
</span>String account = <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">etUsername</span>.getText().toString();
String password = <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">etPassword</span>.getText().toString();
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// 保存用户和密码</span>
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);"></span>ActivityLogin.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">util</span>.saveString(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">ACCOUNT_KEY</span>, account);
ActivityLogin.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">util</span>.saveString(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">PASSWORD_KEY</span>, password);
ConnectionSingleton.getInstance().login(account, password);<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// login

// login success
</span>System.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">out</span>.println(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"login success"</span>);
ActivityLogin.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">mCurrentAccount </span>= account;
System.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">out</span>.println(ConnectionSingleton.getInstance()
.getUser());
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// 登录成功后发现在线状态</span>
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);"></span>Presence presence = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>Presence(Presence.Type.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">available</span>);
ConnectionSingleton.getInstance().sendPacket(presence);

<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// 开始主界面</span>
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);"></span>Intent intent = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>Intent(ActivityLogin.<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">this</span>,
ActivityMain.<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">class</span>);
startActivity(intent);


 

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

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

<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">roster </span><span style="margin: 0px; padding: 0px; color: black;">= ActivityMain.</span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">connection</span><span style="margin: 0px; padding: 0px; color: black;">.getRoster();
</span><pre class="code" style="margin: 0px 40px 0px 20px; padding: 5px; border: 1px solid rgb(192, 192, 192); border-image: none; font-family: Verdana,Helvetica,微软雅黑,Arial,宋体,sans-serif; white-space: pre-wrap; -ms-word-wrap: break-word; background-color: rgb(251, 237, 187);" name="code"><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);"></span> 
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public void </span>updateRoster() {
Collection<RosterEntry> entries = <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">roster</span>.getEntries();
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">for </span>(RosterEntry entry : entries) {
System.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">out</span>.print(entry.getName() + <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">" - " </span>+ entry.getUser() + <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">" - "
</span>+ entry.getType() + <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">" - " </span>+ entry.getGroups().size());
Presence presence = <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">roster</span>.getPresence(entry.getUser());
System.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">out</span>.println(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">" - " </span>+ presence.getStatus() + <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">" - "
</span>+ presence.getFrom());
User user = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>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());
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">userinfos</span>.add(user);
}
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">rosterAdapter</span>.notifyDataSetChanged();
}
 




单人聊天模块

第一次修改:

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

ChatManager chatmanager = ConnectionSingleton.getInstance()
.getChatManager();

<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// get user
</span>Intent intent = getIntent();
String user = intent.getStringExtra(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"user"</span>);
System.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">out</span>.println(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"user:" </span>+ user);
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// new a session
</span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">newChat </span>= chatmanager.createChat(user, <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">null</span>);
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// 监听聊天消息</span>
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">        </span>chatmanager.addChatListener(<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>ChatManagerListenerEx());

<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// send message
</span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">try </span>{
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">newChat</span>.sendMessage(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"im bird man"</span>);

} <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">catch </span>(XMPPException e) {
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// </span><span style="margin: 0px; padding: 0px; color: rgb(127, 159, 191);">TODO </span><span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">Auto-generated catch block
</span>e.printStackTrace();
}


监听类

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public class </span>ChatManagerListenerEx <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">implements </span>ChatManagerListener {

<span style="margin: 0px; padding: 0px; color: rgb(100, 100, 100);">@Override
</span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public void </span>chatCreated(Chat chat, <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">boolean </span>arg1) {
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// </span><span style="margin: 0px; padding: 0px; color: rgb(127, 159, 191);">TODO </span><span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">Auto-generated method stub
</span>chat.addMessageListener(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">ml</span>);
}

}

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public class </span>MessageListenerEx <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">implements </span>MessageListener {

<span style="margin: 0px; padding: 0px; color: rgb(100, 100, 100);">@Override
</span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public void </span>processMessage(Chat arg0, Message message) {
String result = message.getFrom() + <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">":" </span>+ message.getBody();
System.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">out</span>.println(result);
android.os.Message msg = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>android.os.Message();
msg.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">what </span>= 0;
Bundle bd = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>Bundle();
bd.putString(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"msg"</span>, result);
msg.setData(bd);
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">handler</span>.sendMessage(msg);

}
}


 

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

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public </span>Handler <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">handler </span>= <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>Handler() {

<span style="margin: 0px; padding: 0px; color: rgb(100, 100, 100);">@Override
</span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public void </span>handleMessage(android.os.Message msg) {

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">switch </span>(msg.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">what</span>) {
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">case </span>0: {
String result = msg.getData().getString(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"msg"</span>);
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">record</span>.setText(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">record</span>.getText() + <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"\n" </span>+ result);
}
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">break</span>;
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">default</span>:
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">break</span>;
}
}
};


 

aaa跟bbb 的聊天









第二次修改:

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





 

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

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public class </span>XmppMessageManager <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">implements </span>ChatManagerListener {
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">private </span>XMPPConnection _connection;
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">private </span>ChatManager manager = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">null</span>;

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public void </span>initialize(XMPPConnection connection) {
_connection = connection;
manager = _connection.getChatManager();
manager.addChatListener(<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">this</span>);
}

<span style="margin: 0px; padding: 0px; color: rgb(100, 100, 100);">@</span>Override
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public void </span>chatCreated(Chat chat, <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">boolean </span>arg1) {
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// </span><span style="margin: 0px; padding: 0px; color: rgb(127, 159, 191);">TODO </span><span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">Auto-generated method stub
</span>chat.addMessageListener(<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>MessageListener() {
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public void </span>processMessage(Chat newchat, Message message) {
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// 若是聊天窗口存在,将消息转往目前窗口
// 若窗口不存在,创建新的窗口
</span>System.out
.println(message.getFrom() + <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">":" </span>+ message.getBody());

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">if </span>(!ActivityMain.chats.containsKey(message.getFrom())) {
ActivityMain.chats.put(message.getFrom(), newchat);
} <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">else </span>{

}

}
});
}
}


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

 


多人聊天模块

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

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

hostrooms = MultiUserChat.getHostedRooms(ActivityMain.connection,
"conference.zhanghaitao-pc");

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

jid = getIntent().getStringExtra("jid");
 
<span style="margin: 0px; padding: 0px; color: rgb(0, 255, 0);"><span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">   //</span>后面服务名称必需是创建房间的那个服务</span>
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">   </span>String multiUserRoom = jid;
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">try </span>{
muc = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>MultiUserChat(ActivityMain.connection, <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">multiUserRoom</span>);
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">//<span style="margin: 0px; padding: 0px; color: rgb(0, 255, 64);"> </span></span><span style="margin: 0px; padding: 0px; color: rgb(0, 255, 64);">创建聊天室,进入房间后的nickname</span>
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">        </span>muc.join(ActivityLogin.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">mCurrentAccount</span>);

Log.v(TAG, <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"join success"</span>);

} <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">catch </span>(XMPPException <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">e</span>) {
<span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">// </span><span style="margin: 0px; padding: 0px; color: rgb(127, 159, 191);">TODO </span><span style="margin: 0px; padding: 0px; color: rgb(63, 127, 95);">Auto-generated catch block
</span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">e</span>.printStackTrace();
}
ChatPacketListener <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">chatListener </span>= <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span><span style="margin: 0px; padding: 0px; color: blue;">ChatPacketListener</span>(muc);
muc.addMessageListener(chatListener);


 

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

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">class </span>ChatPacketListener <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">implements </span>PacketListener {
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">private </span>String <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">_number</span>;
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">private </span>Date <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">_lastDate</span>;
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">private </span>MultiUserChat <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">_muc</span>;
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">private </span>String <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">_roomName</span>;

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public </span>ChatPacketListener(MultiUserChat muc) {
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">_number </span>= <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"0"</span>;
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">_lastDate </span>= <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>Date(0);
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">_muc </span>= muc;
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">_roomName </span>= muc.getRoom();
}

<span style="margin: 0px; padding: 0px; color: rgb(100, 100, 100);">@Override
</span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">public void </span>processPacket(Packet packet) {
Message message = (Message) packet;
String from = message.getFrom();

<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">if </span>(message.getBody() != <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">null</span>) {
DelayInformation inf = (DelayInformation) message.getExtension(
<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"x"</span>, <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"jabber:x:delay"</span>);
Date sentDate;
<span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">if </span>(inf != <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">null</span>) {
sentDate = inf.getStamp();
} <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">else </span>{
sentDate = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>Date();
}

Log.w(<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">TAG</span>, <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"Receive old message: date="
</span>+ sentDate.toLocaleString() + <span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">" ; message="
</span>+ message.getBody());

android.os.Message msg = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>android.os.Message();
msg.<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">what </span>= <span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">RECEIVE</span>;
Bundle bd = <span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span>Bundle();
bd.putString(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"from"</span>, from);
bd.putString(<span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"body"</span>, message.getBody());
msg.setData(bd);
<span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">handler</span>.sendMessage(msg);
}
}
}


 


下载模块

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

<span style="margin: 0px; padding: 0px; color: black;">FileTransferManager transfer = </span><span style="margin: 0px; padding: 0px; color: rgb(127, 0, 85);">new </span><span style="margin: 0px; padding: 0px; color: black;">FileTransferManager(
ActivityMain.</span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">connection</span><span style="margin: 0px; padding: 0px; color: black;">);
String destination = </span><span style="margin: 0px; padding: 0px; color: rgb(0, 0, 192);">user</span><span style="margin: 0px; padding: 0px; color: black;">;
OutgoingFileTransfer out = transfer
.createOutgoingFileTransfer(destination + </span><span style="margin: 0px; padding: 0px; color: rgb(42, 0, 255);">"/Smack"</span><span style="margin: 0px; padding: 0px; color: black;">);
</span>


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

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


 

网上说文件的传输遇到几个比较重要的问题,我也查看了很多资料(国内的基本是寥寥无几,对此我感到挺无奈的,只能看国外,这样每次我的英语水平都提高了太无奈了^0^)。在这个android asmack的最新版本好像是解决了几个比较重要的问题,剩下一个传输文件没反应的问题我在初始化连接时调用了configure方法解决。不过不知道是不是这个原因,后面出现了一个神奇的问题,就是有时可以成功传输有时传输时客户端没响应(如果有人完美解决了这个问题,那就………赶紧将代码放出来一起共享^-^,以提高我国程序员的整体水平,多伟大遥远的理想啊~~)。

项目下载

http://files.cnblogs.com/not-code/ASmack.zip

本文为原创翻译,如需转载,请注明作者和出处,谢谢!

出处:http://www.cnblogs.com/not-code/archive/2011/07/16/2108369.html

文章其实在一个星期前就写好了, 不过一直忙着看asmack源码,发现有很多可以学习的地方,可以自己定制自己喜欢的类和功能,因此越到后面越发现自己这篇文章很多地方都写得挺简单的,差点就不想发了^-^。不过为了上面那个伟大的理想……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息