zoukankan      html  css  js  c++  java
  • 即时聊天IM之四 Android客户端IM帮助类编写

    图文无关一起娱乐:

    程序员egojit

    这一篇我们开始写Android端的Smack版主类,后面Android的IM功能都是通过这个帮助类实现的

    引用类库:

    因为我用的是IDE是Android Studio,所以我通过gradle进行jar包管理了,非常方便,jar包如下:

    compile 'org.igniterealtime.smack:smack-core:4.1.4'
    compile 'org.igniterealtime.smack:smack-tcp:4.1.4'
    compile 'org.igniterealtime.smack:smack-extensions:4.1.4'
    compile 'org.igniterealtime.smack:smack-android:4.1.4'
    compile 'org.igniterealtime.smack:smack-android-extensions:4.1.4'
    compile 'org.igniterealtime.smack:smack-experimental:4.1.4'
    compile 'org.igniterealtime.smack:smack-bosh:4.1.4'
    compile 'org.igniterealtime.smack:smack-resolver-dnsjava:4.1.4'
    compile 'org.igniterealtime.smack:smack-legacy:4.1.4'
    

     加上这些jar包后我们就可以使用Smack库了,大家很容易看到,我这个是4.1.4的包。它的最新包是4.2.0不过是alpha版本,所以我就用这个4.1.4最新正式包了。它和它的一些老版本差别还是比较大的。所以如果你是第一次使用还是和我一样,防止出现一些问题。更新gradle后就可以使用了。

    写Smack帮助类:

    我这里先定义一个ISmack接口,这种命名方式是我从C#那边带过来的,别纠结。本人很久之前是.NET平台的,.NET平台还是有很多东西是非常不错的。这个接口就是一些约束协议。然后再写了一个Smack 类,它继承并且实现了ISmack接口。

    ISmack接口代码如下:

    /**
     *
     * @备注:samck操作接口协议
     * @作者:高露
     * @时间:2015-10-24
     * @QQ:408365330
     *
     */
    public interface ISmack {
    
    
        /**
         * 登录
         * @param name 账号
         * @param pwd 密码
         * @return
         */
        public boolean login(String name,String pwd);
    
    
        /**
         * 消息发送
         * @param from 谁发送
         * @param to 发送给谁
         * @param content 发送内容
         */
        public void sendMessage(String from,String to,String content) throws SmackException.NotConnectedException;
    
    
        /**
         *添加好友
         * @param user 用户jid
         * @param name 添加好友备注名称
         * @param groups  好友添加到的分组,可以过个组
         */
        public void addRosterItem(String user,String name,String[] groups) throws Exception;
    
        /**
         * 删除好友
         * @param user 好友jid
         */
        public void removeRoster(String user);
    
    
    }

    可以通过这份协议知道我这里定义了 登录,消息发送,添加好友,删除好友 这些方法,后面还是会添加的,每个方法备注还是比较详细的,看看就知道是什么意思了。

    然后我们再看看和分析Smack代码

    Smack代码分析:

    静态构造函数:

    首先定义了一个java静态构造函数

    static {
            if (connection == null) {
                XMPPTCPConnectionConfiguration configuration = XMPPTCPConnectionConfiguration.builder()
                        .setConnectTimeout(Constant.IM_TIMEOUT)
                        .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
                        .setHost(Constant.IM_SERVER)//ip
                        .setPort(Constant.IM_SERVER_PORT)//端口号设置一般式5222
                        .setServiceName(Constant.IM_SERVER_DOMAIN)//服务器名称
                        .setDebuggerEnabled(true)//设置开启调试
                        .setSendPresence(true)//设置是否发送Presece信息
                        .build();
                connection = new XMPPTCPConnection(configuration);
    
                connection.addConnectionListener(new ConnectionListener() {
                    @Override
                    public void connected(XMPPConnection connection) {
                        LogHelper.i(TAG, "connected");
                    }
    
                    @Override
                    public void authenticated(XMPPConnection connection, boolean resumed) {
                        LogHelper.i(TAG, "authenticated");
                    }
    
                    @Override
                    public void connectionClosed() {
                        LogHelper.i(TAG, "connectionClosed");
                    }
    
                    @Override
                    public void connectionClosedOnError(Exception e) {
                        LogHelper.i(TAG, "connectionClosedOnError");
                    }
    
                    @Override
                    public void reconnectionSuccessful() {
                        LogHelper.i(TAG, "reconnectionSuccessful");
                    }
    
                    @Override
                    public void reconnectingIn(int seconds) {
                        LogHelper.i(TAG, "reconnectingIn");
                    }
    
                    @Override
                    public void reconnectionFailed(Exception e) {
                        LogHelper.i(TAG, "reconnectionFailed");
                    }
                });
    
                ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
                reconnectionManager.setFixedDelay(Constant.IM_RE_CONNET_TIME);//重联间隔
                reconnectionManager.enableAutomaticReconnection();//开启重联机制
                try {
                    connection.connect();
                } catch (SmackException | IOException | XMPPException ex) {
                    ex.printStackTrace();
                }
    
    
            }
        }
    XMPPTCPConnectionConfiguration类是连接的配置,连接相关配置都是通过这个类传递给XMPPTCPConnection对象的。配置信息的设置请看上面的代码注释,connection.addConnectionListener是给连接添加监听,这里面我们可以监听连接的各种状态。然后做相应的处理。
    ReconnectionManager这个类是重联管理设置连接断开后是否允许重新连接。这样实现自动重联
    最后通过connection.connect()连接XMPP服务器
    登录:
    /**
         * 登录
         * @param name 账号
         * @param pwd 密码
         * @return
         */
        @Override
        public boolean login(String name, String pwd) {
            try {
                if (connection.isConnected()) {
                    connection.login(name, pwd);
    
                } else {
                    connection.connect();
                    connection.login(name, pwd);
                }
    
            } catch (XMPPException | SmackException | IOException ex) {
                ex.printStackTrace();
            }
    
            /**
             * 消息监听
             */
            registerMessageListener();
            /**
             * 通讯录监听
             */
            registerRosterListener();
            return false;
        }

    通过用户名和密码进行登录。登录之前判断是否连接了XMPP服务器。登录后添加消息监听处理消息,通讯录监听处理通讯录。下面再看看这两个监听方法

    通讯录监听:

    /**
         * 通讯录监听
         */
        private void registerRosterListener() {
            Roster roster = Roster.getInstanceFor(connection);
            roster.setSubscriptionMode(Roster.SubscriptionMode.manual);//设置添加好友,需要对方确认
            roster.addRosterListener(new RosterListener() {
                @Override
                public void entriesAdded(Collection<String> collection) {
                    LogHelper.i(TAG, "通讯录用户添加");
                }
    
                @Override
                public void entriesUpdated(Collection<String> collection) {
                    LogHelper.i(TAG, "通讯录用户变更");
                }
    
                @Override
                public void entriesDeleted(Collection<String> collection) {
                    LogHelper.i(TAG, "通讯录用户删除");
                }
    
                @Override
                public void presenceChanged(Presence presence) {
                    LogHelper.i(TAG, "通讯录用户presence变化");
                }
            });
        }
    Roster类管理这通讯录。给通讯录添加了监听这样可以处理通讯里,请看上面的代码。这里重点讲解roster.setSubscriptionMode(Roster.SubscriptionMode.manual);这个设置通讯里添加好友的模式。这里设置了添加好友需要确认,而不是直接成为好友,一般都是这样,但是这里也支持直接成为好友。我们通过源码来看看SubscriptionMode这个枚举。
    /**
         * 好友请求订阅的模式枚举.
         */
        public enum SubscriptionMode {
    
            /**
             * 自动接收所有好友请求. This is
             * 这是默认的模式,适合简单的客户端. 更复杂的客户端希望手动处理好友添加请求.
             */
            accept_all,
    
            /**
             * 自动拒绝所有请求
             */
            reject_all,
    
            /**
             * 好友请求被忽略,意味着必须手动注册和处理presence监听,然后处理类型是        
    * Presence.Type.SUBSCRIBE类型或者是Presence.Type.UNSUBSCRIBE类型的 presence包
             */
            manual
        }

    以上是我通过源码中的英文转译的,鄙人英文就这水平见谅,见谅。这里说的presence包不懂的话看看第一篇XMPP协议简析,这样就懂了。我的原则是任何东西先懂原理(先修炼好《易筋经》然后再学招式,否则累也记不住,不懂硬记很累,有些学编程,语言没学好然后直接上平台性的东西,发现容易出问题,同样一个道理)。

    消息监听:

    /**
         * 各种消息包监听
         */
        private void registerMessageListener() {
            connection.addSyncStanzaListener(new StanzaListener() {
                @Override
                public void processPacket(Stanza stanza) throws SmackException.NotConnectedException {
                    if (stanza instanceof Message) {//表示接收到是消息包
                        Message message = (Message) stanza;
                        if (message.getType() == Message.Type.chat) {//表示单聊
    
                        }
                        if (message.getType() == Message.Type.groupchat) {//表示群聊
    
                        }
                        if (message.getType() == Message.Type.error) {//表示错误信息
    
                        }
                    }
    
                    if (stanza instanceof Presence) {//表示接收到的是Presence包
    
                    }
    
                    if (stanza instanceof IQ) {//表示接收到的是IQ包
    
                    }
                }
            }, new StanzaFilter() {
                @Override
                public boolean accept(Stanza stanza) {
                    return true;
                }
            });

    虽然还有其它监听消息的方法,但是我选择这种了,因为这种可以监听所有各种消息包,看上面注释能理解。如果不懂这些包神马意思还是推荐你看前面第一篇XMPP协议简析。那么久知道神马是IQ,神马是Message,什么是Presence包了

    new StanzaFilter() {
                @Override
                public boolean accept(Stanza stanza) {
                    return true;
                }
            }

    这个是过滤包,我这里返回ture就是不过滤直接接受所有XMPP包。你还可以过滤特定的包比如IQ包  StanzaFilter filter=new StanzaTypeFilter(IQ.class) ,然后把这个作为 addSyncStanzaListener方法的第二个参数这样就只能接受IQ消息了。

    消息发送

     /**
         * 消息发送
         *
         * @param from    谁发送
         * @param to      发送给谁
         * @param content 发送内容
         */
        @Override
        public void sendMessage(String from, String to, String content) throws SmackException.NotConnectedException {
    
    
            Message msg = new Message(to, content);
            msg.setFrom(from);
            connection.sendStanza(msg);
    
    
    //            ChatManager chatmanager = ChatManager.getInstanceFor(connection);
    //            Chat newChat = chatmanager.createChat(to, new ChatMessageListener() {
    //                @Override
    //                public void processMessage(Chat chat, Message message) {
    //                    LogHelper.i(TAG, "接收到消息:" + message);
    //
    //                }
    //            });
    //           newChat.sendMessage(content);
    
    
        }

    我这里可以看到有两种方式,一种直接原始的发送Message包,另一种就是被我注释的代码段,通过ChatManager来发送消息

    添加好友:

    /**
         * 添加好友
         * @param user 用户jid
         * @param name 添加好友备注名称
         * @param groups  好友添加到的分组,可以过个组
         * @throws Exception
         */
        @Override
        public void addRosterItem(String user, String name, String[] groups) throws Exception{
            Roster roster=Roster.getInstanceFor(connection);
            roster.createEntry(user,name,null);
        }

    这里没神马好讲的,因为上面设置了 roster.setSubscriptionMode(Roster.SubscriptionMode.manual);//设置添加好友,需要对方确认  这种模式,添加好友需要对方确认

    最后:

    今天就此结束,虽然只有这些方法,如果你结合前面第一篇XMPP协议简介弄懂原理,我们就共同进步了:)。希望我们一起每天进步一点。

    合肥程序员群:49313181。    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入)
    Q  Q:408365330     E-Mail:egojit@qq.com
     
  • 相关阅读:
    java执行spark查询hbase的jar包出现错误提示:ob aborted due to stage failure: Master removed our application: FAILED
    java调用scala 查询hbase数据
    spark1.0.2读取hbase(CDH0.96.1)上的数据
    安装Hadoop系列 — 安装SSH免密码登录
    安装Ubuntu双系统系列——更换源
    安装Ubuntu双系统系列——为Firefox安装Adobe Flash Player
    安装Ubuntu双系统系列——64位Ubuntu安装H3C的INode客户端
    安装Ubuntu双系统系列——安装中文输入法
    安装Ubuntu双系统系列——安装Ubuntu
    智传播客hadoop视频学习笔记(共2天)
  • 原文地址:https://www.cnblogs.com/egojit/p/smack_for_android_helper_1.html
Copyright © 2011-2022 走看看