关于XMPP,14年的时候就已经写过几篇博客了,服务器使用Openfire,安卓客户端使用asmack.jar,不过asmack现在已经停止维护,而Openfire和配套的smack.jar则一直在更新,所以这篇博客主要来写如何用最新的openfire4.5.1+smack4.3.4完成XMPP的初步实现!
效果如下图:
上面为安卓客户端和PC端的Spark实现即时聊天,当然可以手机和手机聊。相关资源下载地址:https://igniterealtime.org/downloads/index.jsp
至于Openfire的安装方法,基本跟之前没什么变化,可以参考之前的文章有介绍,在使用Openfire前,请务必安装好数据库,本例中使用的是MySql,安卓完成后,启动Openfire:
客户端:
数据库(数据库名自定义):
表示安装成功!
可以开始写安卓端APP了!
Smack.jar中的方法跟之前的asmack有相似也有区别,首先说Smack最新的登录方式如下:
InetAddress addr = InetAddress.getByName(Const.XMPP_HOST);
HostnameVerifier verifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return false;
}
};
DomainBareJid serviceName = JidCreate.domainBareFrom(Const.XMPP_DOMAIN);//Domain 服务器名称
XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
.setHost(Const.XMPP_HOST)
.setPort(5222)
.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
.setXmppDomain(serviceName)
.setHostnameVerifier(verifier)
.setHostAddress(addr)
.setConnectTimeout(30000)
.build();
xmpptcpConnection = new XMPPTCPConnection(config);
//开启重联机制
// ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(xmpptcpConnection);
// reconnectionManager.setFixedDelay(5);
// reconnectionManager.enableAutomaticReconnection();
//连接
xmpptcpConnection.connect();
//登录
xmpptcpConnection.login(PreferencesUtils.getSharePreStr(context, Const.ACCOUNT), PreferencesUtils.getSharePreStr(context, Const.PWD));
if (xmpptcpConnection.isAuthenticated()) {//登录成功
} else {//登录失败
}
端口5222固定的,其它重要的两个参数:host域名和Domain服务器名称:这是在安装openfire已经设置好的:
这里我将两个名称设置一样了!
注册方法,只要在connect成功后,调用以下方法即可:
AccountManager accountManager = AccountManager.getInstance(xmpptcpConnection);
accountManager.sensitiveOperationOverInsecureConnection(true);
accountManager.createAccount(Localpart.from(username), pwd);
注意XMPP连接等方法需要线程中进行,切记!
监听连接状态addConnectionListener:
ConnectionListener connectionListener = new ConnectionListener() {
@Override
public void connected(XMPPConnection connection) {
}
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
}
@Override
public void connectionClosed() {
}
@Override
public void connectionClosedOnError(Exception e) {
}
};
监听消息接收:
ChatManager.getInstanceFor(xmpptcpConnection).addIncomingListener(new IncomingChatMessageListener() {
@Override
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
}
})
监听消息发送:
ChatManager.getInstanceFor(xmpptcpConnection).addOutgoingListener(new OutgoingChatMessageListener() {
@Override
public void newOutgoingMessage(EntityBareJid from, Message message, Chat chat) {
}
})
发送消息:
EntityBareJid jid = JidCreate.entityBareFrom(to + "@" + Const.XMPP_DOMAIN);
Chat chat = XMPPConnectionUtil.getChatManager().chatWith(jid);
if (chat != null) {
Message message = new Message();
message.setBody(msg);
chat.send(message);
}
接收离线消息:
首先看上面登录的方法中有设置:
.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
此方法表示以离线状态登录,这样才能去接收离线消息,在登录成功后:
OfflineMessageManager offlineMessageManager = new OfflineMessageManager(XMPPConnectionUtil.getInstance());
List<Message> messageList = offlineMessageManager.getMessages();
for (Message message : messageList) {
LogUtil.e("离线消息>>" + message.getBody());
}
offlineMessageManager.deleteMessages();
XMPPConnectionUtil.getInstance().sendStanza(new Presence(Presence.Type.available));
离线消息获取完毕后,将登录状态设置为上线available。
由于smack自带的重连机制并不好用,所以需要我们自己写靠谱的重连机制,我们需要在ConnectionListener做监听,一旦发现连接错误等,变启动重连机制,本项目中做法:
@SuppressLint("HandlerLeak")
public Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull android.os.Message msg) {
super.handleMessage(msg);
LogUtil.e("重新连接>>");
XMPPConnectionUtil.login(mContext, new XMPPConnectionUtil.OnLoginListener() {
@Override
public void onLogin(boolean isLogin, String error) {
if (!TextUtils.isEmpty(error) && error.contains("already logged")) {
handler.removeMessages(0);
return;
}
if (isLogin) {//连接成功
LogUtil.e("连接成功>>");
XMPPConnectionUtil.getInstance().addConnectionListener(connectionListener);
XMPPConnectionUtil.getChatManager().addIncomingListener(incomingChatMessageListener);
XMPPConnectionUtil.getChatManager().addOutgoingListener(outgoingChatMessageListener);
handler.removeMessages(0);
} else {
LogUtil.e("连接失败>>");
handler.sendEmptyMessageDelayed(0, 5000);
}
}
});
}
};
/**
* 连接状态监听
*/
ConnectionListener connectionListener = new ConnectionListener() {
@Override
public void connected(XMPPConnection connection) {
handler.removeMessages(0);
LogUtil.e("connected>>");
}
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
handler.removeMessages(0);
LogUtil.e("authenticated>>" + resumed);
}
@Override
public void connectionClosed() {
removeListener();
handler.sendEmptyMessage(0);
LogUtil.e("connectionClosed>>");
}
@Override
public void connectionClosedOnError(Exception e) {
removeListener();
handler.sendEmptyMessage(0);
LogUtil.e("connectionClosedOnError>>" + e.getMessage());
}
};
项目中也包含了查询用户和好友的方法,简单的基础封装,保持XmppConnect对象单例模式,另外,我将接收消息以及监听连接状态方法写在了MainActivity,而不是像之前一样写在Service,是因为Service管理越来越严格,很容易被杀掉即便应用是打开状态,所以写在ManActivity尽量保证万无一失!
项目地址:
CSDN下载:https://download.csdn.net/download/baiyuliang2013/12375843