Android使用XMPP框架实现即时聊天(IM)功能(Openfire + 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()”函数断开与服务器的连接。

用户注册/登录功能

(一)用户注册功能:

扫描二维码关注公众号,回复: 16032674 查看本文章
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的配置之前也搞了好几天,以后有空的话争取进行补充。
——————————————————————————
最后贴一下我的个人公众号:微信搜索“茶迁”或扫描下图。平时会更新一些编程相关的文章,欢迎大家关注~
茶迁

猜你喜欢

转载自blog.csdn.net/weixin_46269688/article/details/110420351