目录
- 概述
- 前期准备
- 客户端使用Smack
- 权限配置、压缩包导入等
- 客户端连接到服务器
- 用户注册/登录功能
- 离线消息接收
- 接收/发送消息
- 后记
概述
即时聊天功能是许多APP的刚需。QQ、微信等用的都是私有协议,但是个人开发者要短时间内从0到1编写一个即时聊天框架并不现实。现在有许多提供IM功能的框架或公开协议,比如蘑菇街、XMPP等。XMPP虽然存在一些问题,但是推出的早,因此帮助文档较多,对于新手或者时间上较紧迫的开发者来说,用XMPP实现IM功能是一个很好的选择。
前期准备
服务器端需要下载并配置Openfire,而客户端则采用Smack实现。
服务器端建议申请一个云服务器,这样自己的电脑不用时刻开机,而且配置也方便很多。
将服务器端Openfire配置完后,记下自己服务器的域名,这在之后的客户端编程中会用到。
客户端使用Smack
我们以Android Studio编程为例进行演示。
权限配置、压缩包导入等
1.在“AndroidManifest.xml”文件中添加如下代码:
<uses-permission android:name="android.permission.INTERNET" />
上述代码的功能是申请网络使用权限,因为即时聊天需要使用网络。
2.在“build.gradle”文件中添加如下代码:
//导入smack相关
repositories {
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots'
}
mavenCentral()
}
//导入smack相关
implementation 'org.igniterealtime.smack:smack-android-extensions:4.2.0'
implementation 'org.igniterealtime.smack:smack-experimental:4.2.0'
implementation 'org.igniterealtime.smack:smack-tcp:4.2.0'
上述代码的功能是导入Smack相关的资源文件(压缩包)。本文以Android Studio为例,其他平台的资源文件导入方式在官网也都有详细的文档说明。
客户端连接到服务器
具体代码如下:
public AbstractXMPPConnection mConnection(Context context) {
XMPPTCPConnectionConfiguration.Builder configBuilder = XMPPTCPConnectionConfiguration.builder();
//设置XMPP域名
try {
configBuilder.setXmppDomain("0.0.0.0");
} catch (XmppStringprepException e) {
e.printStackTrace();
}
//设置主机位置(即服务器ip)
try {
configBuilder.setHostAddress(InetAddress.getByName("0.0.0.0"));
} catch (UnknownHostException e) {
e.printStackTrace();
}
//设置端口号
configBuilder.setPort(5222);
//设置不验证,否则需要TLS验证
configBuilder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
//设置更改用户当前状态(在线、离线等)
configBuilder.setSendPresence(false);
AbstractXMPPConnection connection = new XMPPTCPConnection(configBuilder.build());
// 连接到服务器
try {
connection.connect();
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XMPPException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return connection;
}
注:
1.上述代码中“0.0.0.0”即前文所提到的自己的服务器域名;
2.建议将所有小功能(如连接到服务器、注册、登录等)分别使用子函数实现,之后作为接口调用。
3.在所有操作做完后,要调用“.disconnect()”函数断开与服务器的连接。
用户注册/登录功能
(一)用户注册功能:
connection = xmppManage.mConnection(LoginActivity.this);
AccountManager accountManager = AccountManager.getInstance(connection);
accountManager.sensitiveOperationOverInsecureConnection(true);
try {
accountManager.createAccount(Localpart.from(Username), Password);
//注册成功,则提示
Toast.makeText(LoginActivity.this,"注册成功,请登录!",Toast.LENGTH_SHORT).show();
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (XmppStringprepException e) {
e.printStackTrace();
}
connection.disconnect();
(二)用户登录功能:
/**
* 用户登录功能实现
*/
public boolean login(String userName, String passWord, AbstractXMPPConnection connect) {
Log.d("记录", "正在登录...");
try {
// 判断是否登录
if (!connect.isAuthenticated()) {
connect.login(userName, passWord);
//接收离线信息,设为离线状态
Presence presence = new Presence(Presence.Type.unavailable);
connect.sendStanza(presence);
Log.d("记录", "登录成功!");
return true;
}
Log.d("记录", "已被登录,登录失败...");
return false;
} catch (XMPPException | SmackException | IOException e) {
e.printStackTrace();
Log.d("记录", "登录出错...");
return false;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
注:登录成功后,要先将用户状态设置为离线,因为在线状态无法接收离线消息。
离线消息接收
代码如下:
/**
* 用户接收离线消息功能实现
*/
public List<Message> getOfflineMessage(AbstractXMPPConnection connection) throws Exception{
//将用户状态设为离线
Presence presence1 = new Presence(Presence.Type.unavailable);
connection.sendStanza(presence1);
OfflineMessageManager offlineManager = new OfflineMessageManager(connection);
//获取离线消息
List<Message> messageList = offlineManager.getMessages();
offlineManager.getHeaders();
int i = offlineManager.getMessageCount();
Log.d("记录", "getMessageCount:"+i);
//获取后删除离线消息记录
offlineManager.deleteMessages();
//将用户状态设为在线
Presence presence = new Presence(Presence.Type.available);
connection.sendStanza(presence);
return messageList;
}
注:1.上面子函数返回的是所有的离线消息;
2.接收离线消息时,要将用户状态设置为离线。
接收/发送消息
(一)接收消息:
/**
* 消息监听,新消息提醒功能实现
*/
public class InChatMessageListener implements IncomingChatMessageListener{
@Override
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
//对接收到的信息进行操作
}
}
注意在退出APP时(调用“onDestroy()方法时”)要移除消息监听(“.removeListener(inListener)”)。
(二)发送消息
代码比较简单,具体如下:
try {
LoginActivity.xmppManage.SendMessage(LoginActivity.connection, ChatActivity.exist_friendname, mecessage_content);
} catch (Exception e) {
e.printStackTrace();
}
后记
1.XMPP还可以实现聊天室(多人聊天)等功能。
2.调试时可以使用Spark,Spark是一个电脑端的软件,也是使用XMPP实现的,功能很丰富。
3.Openfire的配置之前也搞了好几天,以后有空的话争取进行补充。
——————————————————————————