XMPP协议简介
XMPP协议(ExtensibleMessagingandPrenceProtocol,可扩展消息处理现场协议)
是一种基于XML的协议,目的是为了解决及时通信标准而提出来的,最早是在Jabber上
实现的。它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩
展性。并且XML很易穿过防火墙,所以用XMPP构建的应用不易受到防火墙的阻碍。利用
XMPP作为通用的传输机制,不同组织内的不同应用都可以进行有效的通信。
这篇文章有基本的介绍,
/xutaozero21/article/details/4873439
IM
InstantMesnger,及时通信软件,就是大家使用的QQ、MSNMesnger和Gtalk
等等。其中Gtalk就是基于XMPP协议的一个实现,其他的则不是。当前IM几乎作为每
个上网者必然使用的工具,在国外的大型企业中有一些企业级的IM应用,但是其商业价值
还没完全发挥出来。设想既然XMPP协议是一个公开的协议,那么每个企业都可以利用它
来开发适合本身企业工作,提高自身生产效率的IM;甚至,你还可以在网络游戏中集成这
种通信软件,不但让你可以边游戏边聊天,也可以开发出适合游戏本身的IM应用,比如说
一些游戏关键场景提醒功能,团队语音交流等等都可以基于IM来实现。
本文主要讲解在android使用xmpp协议进行即时通信,所涉及3个主要的东西,它们是
openfire、smack和spark,这个三个东东结合起来就是完整的xmppIM实现,这里简
单介绍一下这3个东东在下文的作用:
openfire主要是作为服务器,负责管理客户端的通信连接,以及提供客户端一些通信信息
和连接信息。
Smack主要是xmpp协议的实现,提供了一套很好的api,所以下面操作xmpp都是通过
使用smack的api来实现,当然因为是在android里,所以使用的是asmack这个包,
里面方法跟smack包差不多。
Spark是IM客户端的实现,其实就是使用了smack的api实现的。
下图展示了三者之间的关系:(很明显这个图是偷别人的,具体是哪里我忘了,因为资料都
是复制到文档后慢慢研究看的)
从图上可以了解到,client端和rver端都可以通过插件的方式来进行扩展,smack是
二者传递数据的媒介。
配置openfire服务器
具体步骤请移步:
/blog/static/87/
配置成功如果以后ip地址变了,那肯定又是开不了,解决办法请移步:
/HappySheepherder/article/details/4707124
配置成功后,在服务器创建一个简单的用户来测试,然后安装spark,设置好服务器的ip
与端口,使用刚才创建的用户登录,登录OK说明服务器成功搭建。
AndroidIM功能(因为是测试demo,因此界面超级简陋,代码都是给出重要的一部分,
剩余的可以在最后下面项目查看)
配置要求
android2.2、、myeclip
连接服务器
在打开软件后会开始初始化,完成与openfire服务器的连接,设置一些配置
static{
_ENABLED=true;
finalConnectionConfigurationconnectionConfig=new
ConnectionConfiguration(
host,5222,"");
//Googletalk
//ConnectionConfigurationconnectionConfig=
new
//ConnectionConfiguration(
//"",5222,"");
//
LAuthenticationEnabled(fal);
tion=new
XMPPConnection(connectionConfig);
_ENABLED=true;
ProviderManagerpm=tance();
configure(pm);
}
注册模块
注册有两种方法:一种是用createAccount,不过我测试了一下发现不能创建用户,具体
原因不详,下面介绍第二种。
如上图:注册成功后服务器将多了ggg用户。
具体实现如下:
Registrationreg=newRegistration();
e();
(tance().getService
Name());
rname(t().toString());
sword(t().toString());
ribute("android",
"geolo_createUr_android");
n("reg:"+reg);
PacketFilterfilter=newAndFilter(newPacketIDFilter(reg
.getPacketID()),new
PacketTypeFilter());
PacketCollectorcollector=
tance()
.createPacketCollector(filter);
tance().ndPacket(reg);
result=(IQ)sult(SmackConfiguration
.getPacketReplyTimeout());
//Stopqueuingresults
();
if(result==null){
xt(getApplicationContext(),"服,
_SHORT).show();
}elif(e()==
){
if(or().toString().equalsIgnoreCa(
"conflict(409)")){
xt(getApplicationContext(),"这,
_SHORT).show();
}el{
xt(getApplicationContext(),"注,
_SHORT).show();
}
}elif(e()==
){
xt(getApplicationContext(),"恭,
_SHORT).show();
}
使用注册类,设置好注册的用户名密码和一些属性字段,直接设置包过滤,根据这个过滤创
建一个结果集合,发送注册信息包,等待获取结果,剩余就是判断结果内容.
登录模块
登录比较简单
tance().connect();//connect
Stringaccount=t().toString();
Stringpassword=t().toString();
//保存用户和密码
ring(ACCOUNT_KEY,account);
ring(PASSWORD_KEY,
password);
tance().login(account,
password);//login
//loginsuccess
n("loginsuccess");
ntAccount=account;
n(tance()
.getUr());
//登录成功后发现在线状态
Prenceprence=new
Prence(ble);
tance().ndPacket(prence
);
//开始主界面
Intentintent=newIntent(,
);
startActivity(intent);
获取联系人模块(ActivityMain主界面)
获取联系人并将相关信息保存到一个list数组里,最后通知listview更新界面
roster=ter();
publicvoidupdateRoster(){
Collection
ries();
for(RosterEntryentry:entries){
(e()+"-"+
r()+"-"
+e()+"-"+
ups().size());
Prenceprence=
nce(r());
n("-"+tus()+"-
"
+m());
Urur=newUr();
e(e());
r(r());
e(e());
e(ups().size());
tus(tus());
m(m());
(ur);
}
DataSetChanged();
}
单人聊天模块
第一次修改:
在主界面点击选择一个用户,进入聊天Activity,ActivityChat先获取传过来的用户,创
建聊天类并对该用户设置消息监听
ChatManagerchatmanager=
tance()
.getChatManager();
//getur
Intentintent=getIntent();
Stringur=ingExtra("ur");
n("ur:"+ur);
//newassion
newChat=Chat(ur,null);
//监听聊天消息
tListener(new
ChatManagerListenerEx());
//ndmessage
try{
ssage("imbirdman");
}catch(XMPPExceptione){
//TODOAuto-generatedcatchblock
tackTrace();
}
监听类
publicclassChatManagerListenerEximplements
ChatManagerListener{
@Override
publicvoidchatCreated(Chatchat,booleanarg1){
//TODOAuto-generatedmethodstub
sageListener(ml);
}
}
publicclassMessageListenerEximplements
MessageListener{
@Override
publicvoidprocessMessage(Chatarg0,Message
message){
Stringresult=m()+":"+
y();
n(result);
emsg=e();
=0;
Bundlebd=newBundle();
ing("msg",result);
a(bd);
ssage(msg);
}
}
所获取到的消息都是通过handler来更新UI
publicHandlerhandler=newHandler(){
@Override
publicvoidhandleMessage(emsg){
switch(){
ca0:{
Stringresult=
a().getString("msg");
t(t()+"n"+result);
}
break;
default:
break;
}
}
};
aaa跟bbb的聊天
第二次修改:
第一次的测试,发现如果多个人之间都成为好友,那么他们之间的聊天就出现了接收不到的
信息,当然在跟spark测试时,spark可以收到android端的信息,不过android客户端
是收到这个信息,不过却没有显示出来,具体原因还不太清楚。因此在第二次修改我改成监
听所有聊天信息包,然后再分析包的归属,分发到对应的聊天窗口。
这里就是监听到包后打印的消息,打印出了jid和消息内容
publicclassXmppMessageManagerimplements
ChatManagerListener{
privateXMPPConnection_connection;
privateChatManagermanager=null;
publicvoidinitialize(XMPPConnectionconnection){
_connection=connection;
manager=_tManager();
tListener(this);
}
@Override
publicvoidchatCreated(Chatchat,booleanarg1){
//TODOAuto-generatedmethodstub
sageListener(newMessageListener(){
publicvoidprocessMessage(Chatnewchat,Message
message){
//若是聊天窗口存在,将消息转往目前窗口
//若窗口不存在,创建新的窗口
.println(m()
+":"+y());
if(!nsKey(m()))
{
(m(),newchat);
}el{
}
}
});
}
}
主要就是重写了ChatManagerListener类的监听,分发处理暂时没有想好怎么写。接着
在后台启动rvice就可以开始监听,行了第一次修改那些可以去掉了^0^。
多人聊天模块
也是在主界面的菜单进入ActivityMultiChat,该界面显示所创建的房间,点击就跳转到
ActivityMultiRoom。
获取所有房间比较简单,只需执行下面这段代码
hostrooms=tedRooms(tion,
"aitao-pc");
跳转到后获取要加入的房间的jid,并创建监听。
jid=getIntent().getStringExtra("jid");
//后面服务名称必需是创建房间的那个服务
StringmultiUrRoom=jid;
try{
muc=newMultiUrChat(tion,
multiUrRoom);
//创建聊天室,进入房间后的nickname
(ntAccount);
Log.v(TAG,"joinsuccess");
}catch(XMPPExceptione){
//TODOAuto-generatedcatchblock
tackTrace();
}
ChatPacketListenerchatListener=new
ChatPacketListener(muc);
sageListener(chatListener);
监听大概的流程跟单人聊天差不多,都是handler来操作。不过多人聊天是重写了
PacketListener。具体如下(不过该方法是监听房间的信息,也就是说显示的是以房间为
名字的消息):
classChatPacketListenerimplementsPacketListener{
privateString
_number;
privateDate
_lastDate;
privateMultiUs
erChat_muc;
privateString
_roomName;
publicChatPacketListener(MultiUrChatmuc){
_number="0";
_lastDate=newDate(0);
_muc=muc;
_roomName=m();
}
@Override
publicvoidprocessPacket(Packetpacket){
Messagemessage=(Message)packet;
Stringfrom=m();
if(y()!=null){
DelayInformationinf=(DelayInformation)
ension(
"x","jabber:x:delay");
DatentDate;
if(inf!=null){
ntDate=mp();
}el{
ntDate=newDate();
}
Log.w(TAG,"Receiveoldmessage:date="
+leString()+";message="
+y());
emsg=e();
=RECEIVE;
Bundlebd=newBundle();
ing("from",from);
ing("body",y());
a(bd);
ssage(msg);
}
}
}
下载模块
在主界面对着用户名长按,进入下载activity。进入activityFileTransfer,点击传输按钮
即可将文件传输给之前选择的用户,当然这里做得比较简单,并没有拒绝功能,一旦发现有
文件就接受。
FileTransferM
anagertransfer=newFileTransferManager(
tion);
Stringdestination=ur;
OutgoingFileT
ransferout=transfer
.createOutgoingFileTransfer(destination+
"/Smack");
那用户是如何监听到有文件并且接受呢?在进入主界面的时候就已经开始了一个rvice
(fileListenerService),该服务创建文件的监听类(XmppFileManager),监听类主要
继承FileTransferListener重写里面的fileTransferRequest方法。
FilesaveTo;
//tanswerToforrepliesandnd()
answerTo=
uestor();
if(!_(Environment
.getExternalStorageState())){
nd("ExternalMedianotmountedread/write");
return;
}el
if(!ctory()){
nd("The
directory"+olutePath()
+"isnotadirectory");
return;
}
saveTo=newFile(landingDir,eName());
if(()){
nd("Thefile
"+olutePath()+"alreadyexists");
//delete
();
//return;
}
IncomingFileT
ransfertransfer=();
nd("File
transfer:"+e()+"-"
+
eSize()/1024+"KB");
try{
veFile(saveTo);
nd("File
transfer:"+e()+"-"
+
tus());
doublepercent
s=0.0;
while(!transfe
()){
if(
Status().equals(_progress)){
percents=
((int)(gress()*10000))/100.0;
nd("File
transfer:"+e()+"-"
+percents+
"%");
}elif(tus().equals()){
nd(returnAndLogError(transfer));
return;
}
(1000);
}
if(tus().equals(te)){
nd("vedas"
+
olutePath());
}
el{
nd(returnAndLogError(transfer));
}
}catch(Exceptionex){
Stringmessage="Cannotreceivethefile
becauanerroroccuredduringtheprocess."
+ex;
Log.e(TAG,message,ex);
nd(message);
}
网上说文件的传输遇到几个比较重要的问题,我也查看了很多资料(国内的基本是寥寥无几,
对此我感到挺无奈的,只能看国外,这样每次我的英语水平都提高了太无奈了^0^)。在
这个androidasmack的最新版本好像是解决了几个比较重要的问题,剩下一个传输文件
没反应的问题我在初始化连接时调用了configure方法解决。不过不知道是不是这个原因,
后面出现了一个神奇的问题,就是有时可以成功传输有时传输时客户端没响应(如果有人完
美解决了这个问题,那就………赶紧将代码放出来一起共享^-^,以提高我国程序员的整体水
平,多伟大遥远的理想啊~~)。
项目下载
/not-code/
本文为原创翻译,如需转载,请注明作者和出处,谢谢!
出处:
/not-code/archive/2011/07/16/2108369.h
tml
本文发布于:2022-12-28 15:22:29,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/47351.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |