android移动端xmpp开发入门

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/Achilles_Lee/article/details/78333922

引入

即时通信技术现在已经广泛应用到各种app中了,那么他到底是怎么实现的呢。前段时间因为项目开发的需要,了解学习过一些这方面。这篇文章记录的是我个人了解的一些这方面的知识,如果有错误的地方还请斧正指出,非常感谢。
另外 慕课网中 郭大神的关于xmpp的这个课程也对我学习起到了很大的帮助:http://www.imooc.com/learn/223

xmpp

  • XMPP的前身是Jabber,一个开源形式组织产生的网络即时通信协议。XMPP目前被IETF国际标准组织完成了标准化工作。标准化的核心结果分为两部分; 核心的XML流传输协议 基于XML流传输的即时通讯扩展应用 XMPP的核心XML流传输协议的定义使得XMPP能够在一个比以往网络通信协议更规范的平台上。借助于XML易于解析和阅读的特性,使得XMPP的协议能够非常漂亮。 XMPP的即时通讯扩展应用部分是根据IETF在这之前对即时通讯的一个抽象定义的,与其他业已得到广泛使用的即时通讯协议,诸如AIM,QQ等有功能完整,完善等先进性。
  • 上面是xmpp的官方解释,其实我每次看完官方解释,总是懵懵的。好像什么都知道了,也好像什么都不知道。不过在我了解过之后简单总结看来,xmpp就像上面说的,是一套协议。里面定义了很多xml格式的文本。比如当我们要登录到服务器时,怎么告诉服务器呢。按照xmpp协议中的规范封装一段xml的字符串以流的方式传给服务器就好了。以最简单的发送一个消息举例:
    这里写图片描述
    1. suke 发送给 beta 一条消息,消息的类型是chat(聊天),消息的内容是 who are you ?。
  • 总结以上,在我理解看来,xmpp 就像是我们平时说话使用的语言,服务器和客户端都遵循这样的规范,比我message 代表一个消息。这样到客户端想给服务器发送一条消息时,就拼装一个以message开头的xml字符串流到服务器。服务器按照xmpp的协议,就知道这是一条消息。听起来感觉傻乎乎的。可是xmpp就是这样的。
  • 如果想深入了解xmpp协议,请搜索《xmpp权威指南》,英文版本和中文版本的都有。

IM即时通信软件该怎么做

  • 目前网上比较主流的是采用开源的 openfire服务器+smack sdk 进行开发。smack是一个封装了tcp连接和xmpp协议解析的sdk。
    smack的资料可以移步github:https://github.com/igniterealtime/Smack/wiki/Smack-4.2-Readme-and-Upgrade-Guide
    里面提供了详尽的API,对应的,我也写了一个小demo,连接地址 : https://github.com/Lilee902/mXmpp
  • 我们都知道即时通信是需要做长连接的,而openfire和smack之间的连接采用的是tcp长连接。大家一定都知道心跳包和保持在线,断线重连之类的,我刚开始入手的时候也不知道怎么弄。看了文章开头郭大神的那个基于xmpp的推送后,对于其中的原理不能说豁然开朗吧,也算窥探到了一二。我在这里就不赘述了,那个视频已经讲的很明白了。

Smack怎么用

  • 连接到服务器。

    • Constant.HOST_SERVER 为服务器IP地址,运行demo时需要修改。
                      InetAddress addr = InetAddress.getByName(Constant.HOST_SERVER);
                    HostnameVerifier verifier = new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            return false;
                        }
                    };
                    DomainBareJid serviceName = JidCreate.domainBareFrom(Constant.HOST_SERVER);
                    XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
                            .setHost(Constant.HOST_SERVER) // it will be resolved by setHostAddress method
                            .setUsernameAndPassword(username, pwd)
                            .setPort(Constant.HOST_PORT)
                            .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
                            .setXmppDomain(serviceName)
                            .setHostnameVerifier(verifier)
                            .setHostAddress(addr)
                            .setDebuggerEnabled(true)
                            .build();
    
                    connection = new XMPPTCPConnection(config);
                    connection.connect();
  • 连接之后,就是登录和获取好友列表(花名册)了。具体的实现

    • roster.addRosterLoadedListener(new RosterLoadedListener() {});这个是添加一个监听,因为再刚登录的时候,直接去获取花名册,服务器返回的经常为空集合。网上有人建议在登录成功之后让线程睡100毫秒,不过还是添加listener优雅一点。

         if (connection.isConnected()) {
                      try {
                          connection.login();
                      } catch (Exception e) {
                          android.os.Message msg = android.os.Message.obtain();
                          msg.what = LOGIN_FAILED;
                          handler.sendMessage(msg);
                      }
                      // Thread.sleep(100);
                      Roster roster = Roster.getInstanceFor(connection);
                      roster.addRosterLoadedListener(new RosterLoadedListener() {
                          @Override
                          public void onRosterLoaded(Roster roster) {
                              Logger.e(TAG,"Get roster success ... " );
                              android.os.Message msg = android.os.Message.obtain();
                              msg.what = LOGIN_SUCCESS;
                              msg.obj = roster;
                              handler.sendMessage(msg);
                          }
      
                          @Override
                          public void onRosterLoadingFailed(Exception exception) {
                              Logger.e(TAG,"Get roster failed : " + exception.getMessage());
                          }
                      });
                      android.os.Message msg = android.os.Message.obtain();
                      msg.what = LOGIN_SUCCESS;
                      msg.obj = roster;
                      handler.sendMessage(msg);
                  } else {
                      android.os.Message msg = android.os.Message.obtain();
                      msg.what = CONNECTION_FAILED;
                      handler.sendMessage(msg);
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
  • 创建聊天室

        private void createChatRoom() {
            // 设置聊天监听器,监听聊天消息
            chatManager = ChatManager.getInstanceFor(connection);
            chatManager.addIncomingListener(mIncomingChatMessageListener);
        }
    
    IncomingChatMessageListener mIncomingChatMessageListener = new IncomingChatMessageListener() {
    //接收消息
        @Override
        public void newIncomingMessage(EntityBareJid from, Message message, org.jivesoftware.smack.chat2.Chat chat) {
            String str = chatMap.get(from.toString());
            String name = from.getLocalpart().toString();
            String msg = message.getBody();
            String type = message.getType().toString();
            if (str == null) {
                str = name + " : " + type + " : " + msg + "\n";
            } else {
                str += name + " : " + type + " : " + msg + "\n";
            }
            chatMap.put(from.toString(), str);
            mainBinding.tvChatCon.setText(str);
        }
    };
    
    //发送消息
    private void sendmsg(String msg, RosterEntry rosterEntry, Message.Type type) {
        Chat currentChat;
        try {
            String jidStr = rosterEntry.getJid().toString();
            EntityBareJid jid = JidCreate.entityBareFrom(jidStr);
            currentChat = chatManager.chatWith(jid);
            Message newMessage = new Message();
            newMessage.setBody(msg);
            newMessage.setType(type);
            currentChat.send(newMessage);
    
            String str = chatMap.get(jidStr);
            if (str == null) {
                str = username + " : " + msg + "\n";
            } else {
                str += username + " : " + msg + "\n";
            }
            chatMap.put(jidStr, str);
            mainBinding.tvChatCon.setText(str);
            mainBinding.etWillSendMsg.setText("");
        } catch (SmackException.NotConnectedException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (XmppStringprepException e) {
            e.printStackTrace();
        }
    }

    总结

    其实对于xmpp,我现在也只是略微了解一些,上面这些,希望对有这方面需求的同学有所帮助。郭大神的那个视频和xmpp权威指南真的很值得阅读。视频有助于理解客户端与服务器的连接实现,而xmpp权威指南中会告诉你xmpp协议都定义了那些功能(节的概念,发送消息,出席状态,状态订阅,多设备登录哪个优先,发送文件是怎么实现的,为什么只能发送小文件等等很多很多),了解了这些功能也有助于使用smack这个sdk,同时给扩展做好准备。
    好了,希望以上这些,可以对大家有些许帮助,谢谢。

猜你喜欢

转载自blog.csdn.net/Achilles_Lee/article/details/78333922