当前位置: 首页 > news >正文

XMPP学习——2、用户登录

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

最近在学习XMPP的使用,打算完成一个完整较为完整地Demo示例,通过这个示例掌握xmpp的使用与开发。同时打算在这个示例中学习使用一下其他的开源类库,在此作为记录学习。

包括服务器端——Openfire,客户端——Spark,XMPP 传输协议的实现——Smack(XMPP是一个协议,协议是需要实现的,Smack起到的就是这样的一个作用,android开发使用的是asmack类库)。三者都是基于Java 语言的实现,因此对于熟悉Java 的开发者来说不是很难。

 

OpenFire介绍

Openfire 采用Java开发,开源的实时协作(RTC)服务器基于XMPP(Jabber)协议。

您可以使用它轻易的构建高效率的即时通信服务器.

Openfire安装和使用都非常简单,并利用Web进行管理。单台服务器可支持上万并发用户。

由于是采用开放的XMPP协议,您可以使用各种支持XMPP协议的IM客户端软件登陆服务.

Spark介绍

Spark 提供了客户端一个基本的实现,并提出了一个很好的插件架构,这对于开发者来说不能不说是一个福音。我强烈建议基于插件方式来实现你新增加的功能,而不是去改它的源代码,这样有利于你项目架构,把原始项目的影响降到最低,文章以后的部分也是基于这种插件体系进行开发的

Asmack介绍

smack的Android版本,虽然Smack在PC上可以工作的很好,功能也很强大,但在Android平台上有一些问题,而导致这些问题的原因是Android精简了Java的类库,以至Smack使用的部分类库在Android平台上无法找到,所以Smack不能直接在Android平台上使用.但在2010年初,有人在code.google.com网站上发布了一个Asmack,其中A库就代表Android中的A,也就是说,这个版本是Smack的Android版本.可使用下面地址下载Asmack:

http://code.google.com/p/asmack/downloads/list

下载asmack-2010.03.03.jar文件后,直接在Android工程中引用即可

关系图

1

 

登陆操作界面:

若水GIF截图_2014年1月13日21点5分26秒

示意说明:

1、输入用户名、密码、服务器地址,可以在搭建好openfire服务器后用spark注册账号,类似qq,多注册几个作为测试用,我用spark建立账号名和密码都为test,在此账号创建2个组,我的好友和大学同学,同时注册test1-test4的测试账号,加test为好友,当然这些都可以用代码操作,初始阶段我是这么做快速写代码测试。

2、输入错误的账号和密码会看到信息展示在登陆失败后将错误信息展示出来

3、当输入正确用户名和密码之后,进入mainActivity界面,这里将分组和所有好友以文字形式展现出来

 

代码:

XMPPManager.java

package manager;import org.jivesoftware.smack.*;import org.jivesoftware.smack.provider.ProviderManager;import org.jivesoftware.smackx.GroupChatInvitation;import org.jivesoftware.smackx.PrivateDataManager;import org.jivesoftware.smackx.packet.*;import org.jivesoftware.smackx.provider.*;import org.jivesoftware.smackx.search.UserSearch;import java.util.Collection;import java.util.Iterator;/**
 * User: Coolwxb
 * Date: 14-1-13
 * Time: 下午5:10 */public class XMPPManager {private static XMPPManager instance = null;
    XMPPConnection connection=null;private static String URL = "10.0.0.14";private static int PORT = 5222;private static String DEVICE = "pc";private static String USERNAME = "test";private static String PASSWORD = "test";private static int SUCCESS=0;private XMPPManager( ){/**Manages providers for parsing custom XML sub-documents of XMPP packets. Two types of providers exist:
        IQProvider -- parses IQ requests into Java objects.
        PacketExtension -- parses XML sub-documents attached to packets into PacketExtension instances.
         **/ProviderManager pm = ProviderManager.getInstance();
        configure(pm);
    }/** * 单例方法
     * @return */public static XMPPManager getInstance() {if (instance == null) {
            instance = new XMPPManager();
        }return instance;
    }/** * 获得connection连接
     * @return */public XMPPConnection getConnection() throws Exception {if (connection == null)throw new Exception("请先初始化xmppconnection");return connection;

    }/** *
     * 登陆操作  返回String 来判断登陆结果
     Code XMPP Error Type
     500 interna-server-error WAIT
     403 forbidden AUTH
     400bad-request MODIFY
     404 item-not-found CANCEL
     409 conflict CANCEL
     501 feature-not-implemented CANCEL
     302 gone MODIFY
     400 jid-malformed MODIFY
     406 no-acceptable MODIFY
     405 not-allowed CANCEL
     401 not-authorized AUTH
     402 payment-required AUTH
     404 recipient-unavailable WAIT
     302 redirect MODIFY
     407 registration-required AUTH
     404 remote-server-not-found CANCEL
     504 remote-server-timeout WAIT
     502 remote-server-error CANCEL
     500 resource-constraint WAIT
     503 service-unavailable CANCEL
     407 subscription-required AUTH
     500 undefined-condition WAIT
     400 unexpected-condition WAIT
     408 request-timeout CANCEL
     *
     * @param username
     * @param password
     * @param server*/public String isLogin(String username, String password, String server) {try {
            ConnectionConfiguration cf = new ConnectionConfiguration(
                    server,
                    PORT,
                    DEVICE);
            cf.setDebuggerEnabled(true);  //开启debug模式cf.setCompressionEnabled(false);  //是否对流进行压缩cf.setSASLAuthenticationEnabled(false); //是否开启SASL 登陆验证connection = new XMPPConnection(cf);
            connection.connect();
            connection.login(username, password);return SUCCESS+"";
        } catch (XMPPException e) {return e.getMessage();
        }
    }public void configure(ProviderManager pm) {// Private Data Storagepm.addIQProvider("query", "jabber:iq:private",new PrivateDataManager.PrivateDataIQProvider());// Timetry {
            pm.addIQProvider("query", "jabber:iq:time",
                    Class.forName("org.jivesoftware.smackx.packet.Time"));
        } catch (ClassNotFoundException e) {
        }// XHTMLpm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im",new XHTMLExtensionProvider());// Roster Exchangepm.addExtensionProvider("x", "jabber:x:roster",new RosterExchangeProvider());// Message Eventspm.addExtensionProvider("x", "jabber:x:event",new MessageEventProvider());// Chat Statepm.addExtensionProvider("active","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());
        pm.addExtensionProvider("composing","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());
        pm.addExtensionProvider("paused","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());
        pm.addExtensionProvider("inactive","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());
        pm.addExtensionProvider("gone","http://jabber.org/protocol/chatstates",new ChatStateExtension.Provider());// FileTransferpm.addIQProvider("si", "http://jabber.org/protocol/si",new StreamInitiationProvider());// Group Chat Invitationspm.addExtensionProvider("x", "jabber:x:conference",new GroupChatInvitation.Provider());// Service Discovery # Itemspm.addIQProvider("query", "http://jabber.org/protocol/disco#items",new DiscoverItemsProvider());// Service Discovery # Infopm.addIQProvider("query", "http://jabber.org/protocol/disco#info",new DiscoverInfoProvider());// Data Formspm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());// MUC Userpm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user",new MUCUserProvider());// MUC Adminpm.addIQProvider("query", "http://jabber.org/protocol/muc#admin",new MUCAdminProvider());// MUC Ownerpm.addIQProvider("query", "http://jabber.org/protocol/muc#owner",new MUCOwnerProvider());// Delayed Deliverypm.addExtensionProvider("x", "jabber:x:delay",new DelayInformationProvider());// Versiontry {
            pm.addIQProvider("query", "jabber:iq:version",
                    Class.forName("org.jivesoftware.smackx.packet.Version"));
        } catch (ClassNotFoundException e) {
        }// VCardpm.addIQProvider("vCard", "vcard-temp", new VCardProvider());// Offline Message Requestspm.addIQProvider("offline", "http://jabber.org/protocol/offline",new OfflineMessageRequest.Provider());// Offline Message Indicatorpm.addExtensionProvider("offline","http://jabber.org/protocol/offline",new OfflineMessageInfo.Provider());// Last Activitypm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider());// User Searchpm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());// SharedGroupsInfopm.addIQProvider("sharedgroup","http://www.jivesoftware.org/protocol/sharedgroup",new SharedGroupsInfo.Provider());// JEP-33: Extended Stanza Addressingpm.addExtensionProvider("addresses","http://jabber.org/protocol/address",new MultipleAddressesProvider());

    }/** * 返回组信息的容器
     * @param roster
     * @return */public Iterator<RosterGroup> getGroups(Roster roster) {
        Collection<RosterGroup> rosterGroups = roster.getGroups();return rosterGroups.iterator();
    }

}

&#160;

这里写了个XMPPManager作为帮助类,主要重要的方法就是对xmppconnection做初始化,可看到configure方法对用xml描述的xmpp包做解析,官方文档是这样对ProviderManager这个类做解释:

&#160;

Manages providers for parsing custom XML sub-documents of XMPP packets.

 

Two types of providers exist:

IQProvider -- parses IQ requests into Java objects. 
PacketExtension -- parses XML sub-documents attached to packets

 

into PacketExtension instances.

&#160;

LoginActivity.java

package com.example.XMPPDemo;import android.app.Activity;import android.app.ProgressDialog;import android.content.Intent;import android.os.AsyncTask;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import manager.XMPPManager;import org.jivesoftware.smack.XMPPConnection;/**
 * User: Coolwxb
 * Date: 14-1-13
 * Time: 下午5:18 */public class LoginActivity extends Activity{private XMPPManager xmppManager;private XMPPConnection xmppConnection;private Button btn_login;private EditText et_username;private EditText et_password;private EditText et_server;private TextView tv_info;
    ProgressDialog pd;

    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.login);
        et_password = (EditText) findViewById(R.id.et_password);
        et_username = (EditText) findViewById(R.id.et_username);
        et_server = (EditText) findViewById(R.id.et_server);
        tv_info = (TextView) findViewById(R.id.tv_info);
        btn_login = (Button) findViewById(R.id.btn_login);
        btn_login.setOnClickListener(new View.OnClickListener() {
            @Overridepublic void onClick(View v) {
                login();
            }
        });
    }private void login() {new AsyncTask< String, String, String > (){
            String username = "";
            String password = "";
            String server = "";
            @Overrideprotected void onPreExecute() {
                username = et_username.getText().toString().trim();
                password = et_password.getText().toString().trim();
                server = et_server.getText().toString().trim();
                xmppManager = XMPPManager.getInstance();
                pd = new ProgressDialog(LoginActivity.this);
                pd.setTitle("提示");
                pd.setMessage("正在登陆。。。。");
                pd.show();
            }
            @Overrideprotected String doInBackground(String... strings) {               return xmppManager.isLogin(username,password,server);
        }
            @Overrideprotected void onPostExecute(String info) {
                pd.dismiss();if ("0".equals(info)){//成功登陆SUCCESSIntent intent = new Intent();
                        intent.setClass(LoginActivity.this, MainActivity.class);
                        startActivity(intent);
                }else {
                    Log.e("error",info);
                    tv_info.setText(info);
                }
            }
        }.execute(null,null,null);
    }
}

这里使用了一个android 的异步线程类AsyncTask,在doInBackground方法中做一些耗时的操作,我试过如果不加入线程中操作的话会出现假死现象,所以在这里我将登陆连接放入了线程中.

&#160;

MainActivity.java

package com.example.XMPPDemo;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.widget.TextView;import manager.XMPPManager;import org.jivesoftware.smack.Roster;import org.jivesoftware.smack.RosterEntry;import org.jivesoftware.smack.RosterGroup;import java.util.Collection;import java.util.Iterator;/**
 * User: Coolwxb
 * Date: 14-1-13
 * Time: 下午6:28 */public class MainActivity extends Activity{
    XMPPManager xmppManager;private TextView tv_groupInfo;
    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_groupInfo = (TextView) findViewById(R.id.tv_groupinfo);
        xmppManager = XMPPManager.getInstance();
        Roster roster = null;try {
            roster = xmppManager.getConnection().getRoster();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Iterator<RosterGroup> rosterGroupIterator = xmppManager.getGroups(roster);
        StringBuilder sb = new StringBuilder();//获取所有组信息if (rosterGroupIterator.hasNext()){  //如果有分组while (rosterGroupIterator.hasNext()) {
            RosterGroup rosterGroup = rosterGroupIterator.next();
            String groupName = rosterGroup.getName();int count = rosterGroup.getEntryCount();
            sb.append(rosterGroup.getName()+"\r\n");
        }
        tv_groupInfo.setText("组信息:+\r\n"+sb.toString());
         }else{
            tv_groupInfo.setText("没有组信息");
        }//获取所有人Collection<RosterEntry> iterator  =roster.getEntries();
        Iterator<RosterEntry> entryIterator = iterator.iterator();
        sb = new StringBuilder();while (entryIterator.hasNext()) {
            RosterEntry rosterEntry = entryIterator.next();
            sb.append(rosterEntry.getName()+"\r\n");
        }
        String ii = sb.toString();
        Log.i("info", ii);
        tv_groupInfo.append("所有的成员:+\r\n"+ii);

    }
}

MainActivity的界面中我只放入了一个textview,用来显示分组信息和成员。因为在操作开始我用spark向test这个账号建立了分组和好友,所以会获取到。

登陆就介绍到这里,跳转到mainactivity获取组信息和成员信息涉及比较多的常用类,打算专门研究下专门写一章。

&#160;

最后附上一些比较重要的东东,希望大家会喜欢,同时也希望大家提出宝贵意见,大家共同进步。

&#160;

登陆源码:

重新分享了下:

要XMPP登陆DEMO源码的点我!。。。。

xmpp帮助文档:

要英文官方chm格式指导手册的点我!。。。

要chm格式的XMPP协议API文档的点我!。。。。

asmack jar包

要开发asmack 开发jar包的点我!。。。。

&#160;

最后吐槽下windows live writer 今天用的好卡。。。卡死3次。。什么心情。。

转载于:https://my.oschina.net/coolwxb/blog/192733

相关文章:

  • 建设网站购物平台你需要知道的五个方面
  • MySql FOR UPDATE 锁的一点问题……
  • FineUploader 学习笔记
  • 大一下学期,大二上学期,这一年
  • mysql 关于自增字段的一些说明
  • Hyper-v学习(三),虚拟机实时迁移之存储迁移
  • Jquery - 属性选择器
  • typeof instanceof
  • HashMap vs. TreeMap vs. Hashtable vs.LinkedHashMap
  • 第二十二课:磁滞和麦克斯韦方程组
  • JOOMLA中文安装时 数据库发生错误解块办法
  • haproxy介绍
  • 毕设问题小记——Spring事务配置
  • 对象.delegate=self的理解
  • vsftp虚拟用户配置
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • 5、React组件事件详解
  • CSS 三角实现
  • Docker容器管理
  • Python连接Oracle
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • React中的“虫洞”——Context
  • vue-cli3搭建项目
  • 阿里云Kubernetes容器服务上体验Knative
  • 基于 Babel 的 npm 包最小化设置
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 责任链模式的两种实现
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 字符串匹配基础上
  • 1.Ext JS 建立web开发工程
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • #git 撤消对文件的更改
  • #includecmath
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • ()、[]、{}、(())、[[]]命令替换
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (二)PySpark3:SparkSQL编程
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (九)信息融合方式简介
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (转)h264中avc和flv数据的解析
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .net framework 4.0中如何 输出 form 的name属性。
  • .NET 常见的偏门问题
  • .net 生成二级域名
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • /bin/bash^M: bad interpreter: No such file or directory