即时聊天IM之四 Android客户端IM帮助类编写

图文无关一起娱乐:

这一篇我们开始写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:[email protected]

时间: 2024-10-07 07:07:22

即时聊天IM之四 Android客户端IM帮助类编写的相关文章

android 客户端支付宝 php服务器端编写

生成私钥 输入"genrsa -out rsa_private_key.pem 1024"命令,回车后,在当前 bin 文件目 录中会新增一个 rsa_private_key.pem 文件,其文件为原始的商户私钥(请妥善保 存该文件,PHP 开发语言中需要使用该文件), 生成公钥 输入"rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem"命令回车 后,在当前 bin 文件目录中会新增一个 rsa_p

[PHP]AES加密----PHP服务端和Android客户端

本文采取128位AES-CBC模式加密和解密 1.首先对服务端安装mcrypt: sudo apt-get install php5-mcrypt php5-dev sudo php5enmod mcrypt sudo service apache2 restart 2.PHP服务端AES加密类代码 class MCrypt { private $iv = 'fedcba9876543210'; //初始化向量iv public $key;//AES加密的密钥key //将密钥$key传进本类

即时聊天IM之三 XMPP协议客户端库的和Android端框架概述

合肥程序员群:49313181.    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q  Q:408365330     E-Mail:[email protected] smack介绍: 上一篇我介绍了服务端openfire整合现有系统用户,当服务器整合并且搭建完成后,需要做的工作就是写客户端聊天工具了.要么基于pc要么基于移动(Android和IOS).所以这一篇我们一起学习一下smack库,smack是用java写的开源客户端XMPP (Jabber)库,在老版本

【原创】轻量级即时通讯技术MobileIMSDK:Android客户端开发指南

申明:MobileIMSDK 目前为个人维护的原创开源工程,现陆续整理了一些资料,希望对需要的人有用.如需与作者交流,见文章底签名处,互相学习. MobileIMSDK开源工程的代码托管地址请进入 [email protected]:点击进入 MobileIMSDK的Android客户端SDK文档:点击进入 学习交流 讨论学习和资料区:点此进入 推荐 移动端即时通讯交流: 215891622 推荐 bug/建议发送至:[email protected] [写在前面] MobileIMSDK的An

Dollars即时聊天客户端应用源码

这个源码项目是一款Dollars即时聊天客户端应用源码,源码也比较简单的,希望这个案例能够帮到大家的学习和使用. 源码下载: http://code.662p.com/view/6725.html     An Instant Message Client by XMPP on iPhone使用XMPP实现的iPhone上的聊天工具.只完成了一小部分功能. 登录和注册; 获取联系人列表; 添加好友; 接受好友; 与好友聊天; 获取多人聊天房间列表; 加入房间; 房间内多人聊天; 修改个人状态;目

android毗邻(Pilin)即时聊天应用源码

毗邻(Pilin)即时聊天应用源码,承诺的 基于xmpp openfire asmack 的即时聊天应用,继续完善,现在只完成了文字.表情.图片的发送.有兴趣的朋友可以继续去完善,不过老实说,代码写得很垃圾,没有什么层次,因为这是本人第一个写得App,由于想学习嘛,所以没有用到什么框架,很多重复.冗余的代码,注释比较少, 望大家见谅,大神忽喷. 这里提示几点: 1.必须有网络才能打开app(无网络的本地数据保存与加载--就是进入界面的初始化数据,大家可以自己完善) 2.定位功能需要百度key 3

Mina框架的学习笔记——Android客户端的实现

Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架.当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发.串口通讯程序(只在最新的预览版中提供),MINA 所支持的功能也在进一步的扩展中.目前正在使用 MINA 的软件包括有:Apache Directory Project.Asyn

Android客户端与本地服务器Socket通信

Android客户端与本地服务器Socket通信 Socket服务器运行结果图?? 一.客户端和服务器端的选择: 客户端是我们手机端,关于服务器端,只要安装了JDK,自然就拥有通讯的功能,我们只需要在Eclipse或者MyEclipse中写好文章中服务器端的代码,运行起来即可,用accept()方法启动服务器端,等待客户端的连接,在未连接的情况下,服务器端处于堵塞的状态. 二.客户端注意事项 andriod客户端添加网络访问权限 <uses-permission android:name="

php+ajax长轮询实现web即时聊天

web im的实现方式有很多种: 1.普通轮询,原理通过js定时重复发送ajax请求服务端,获取数据后显示. 2.长轮询,ajax请求服务端,服务端有数据会立即返回,服务端无数据时,会一直等待,直到有数据了才立即范围. 3.socket长连接. 特征分析: 方法1:实现起来最容易,定时重复请求服务端会产生无意义的http连接,消耗服务端资源,实时性较差. 方法2:实现起来较容易,会减少无效的ajax请求产生的http连接,能即时返回数据,但服务端会一直挂着,会消耗一定的资源,处理并发能力不强,比