XMPP学习——2、用户登录
最近在学习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、输入用户名、密码、服务器地址,可以在搭建好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 Storage
pm.addIQProvider("query", "jabber:iq:private",
new PrivateDataManager.PrivateDataIQProvider()); // Time
try {
pm.addIQProvider("query", "jabber:iq:time",
Class.forName("org.jivesoftware.smackx.packet.Time"));
} catch (ClassNotFoundException e) {
} // XHTML
pm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im",
new XHTMLExtensionProvider()); // Roster Exchange
pm.addExtensionProvider("x", "jabber:x:roster",
new RosterExchangeProvider());
// Message Events
pm.addExtensionProvider("x", "jabber:x:event",
new MessageEventProvider());
// Chat State
pm.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()); // FileTransfer
pm.addIQProvider("si", "http://jabber.org/protocol/si",
new StreamInitiationProvider()); // Group Chat Invitations
pm.addExtensionProvider("x", "jabber:x:conference",
new GroupChatInvitation.Provider());
// Service Discovery # Items
pm.addIQProvider("query", "http://jabber.org/protocol/disco#items",
new DiscoverItemsProvider());
// Service Discovery # Info
pm.addIQProvider("query", "http://jabber.org/protocol/disco#info",
new DiscoverInfoProvider());
// Data Forms
pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());
// MUC User
pm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user",
new MUCUserProvider());
// MUC Admin
pm.addIQProvider("query", "http://jabber.org/protocol/muc#admin",
new MUCAdminProvider());
// MUC Owner
pm.addIQProvider("query", "http://jabber.org/protocol/muc#owner",
new MUCOwnerProvider());
// Delayed Delivery
pm.addExtensionProvider("x", "jabber:x:delay",
new DelayInformationProvider());
// Version
try {
pm.addIQProvider("query", "jabber:iq:version",
Class.forName("org.jivesoftware.smackx.packet.Version"));
} catch (ClassNotFoundException e) {
}
// VCard
pm.addIQProvider("vCard", "vcard-temp", new VCardProvider());
// Offline Message Requests
pm.addIQProvider("offline", "http://jabber.org/protocol/offline",
new OfflineMessageRequest.Provider());
// Offline Message Indicator
pm.addExtensionProvider("offline",
"http://jabber.org/protocol/offline",
new OfflineMessageInfo.Provider());
// Last Activity
pm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider());
// User Search
pm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());
// SharedGroupsInfo
pm.addIQProvider("sharedgroup",
"http://www.jivesoftware.org/protocol/sharedgroup",
new SharedGroupsInfo.Provider());
// JEP-33: Extended Stanza Addressing
pm.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();
} }
这里写了个XMPPManager作为帮助类,主要重要的方法就是对xmppconnection做初始化,可看到configure方法对用xml描述的xmpp包做解析,官方文档是这样对ProviderManager这个类做解释:
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.
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; @Override
protected 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() {
@Override
public void onClick(View v) {
login();
}
});
} private void login() {
new AsyncTask< String, String, String > (){
String username = "";
String password = "";
String server = "";
@Override
protected 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();
}
@Override
protected String doInBackground(String... strings) {
return xmppManager.isLogin(username,password,server);
}
@Override
protected void onPostExecute(String info) {
pd.dismiss();
if ("0".equals(info)){
//成功登陆SUCCESS
Intent 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方法中做一些耗时的操作,我试过如果不加入线程中操作的话会出现假死现象,所以在这里我将登陆连接放入了线程中.
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;
@Override
protected 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获取组信息和成员信息涉及比较多的常用类,打算专门研究下专门写一章。
最后附上一些比较重要的东东,希望大家会喜欢,同时也希望大家提出宝贵意见,大家共同进步。
登陆源码:
xmpp帮助文档:
asmack jar包
最后吐槽下windows live writer 今天用的好卡。。。卡死3次。。什么心情。。
XMPP学习——2、用户登录的更多相关文章
- Flask学习之五 用户登录
英文博客地址:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins 中文翻译地址:http:// ...
- python 初学习 模拟用户登录
#!/usr/bin/env python#coding:utf-8''' 2017年8月19日 模拟用户登录,userfile 文件保存字典 用户名,和密码 sorryname 文件保存字典 登录过 ...
- 「Django」rest_framework学习系列-用户登录
用户POST登录-->后台验证用户名密码-->验证正确返回TOKEN-->验证错误返回错误信息 class UserAPI(APIView): #用户登录类 def post(sel ...
- AngularJs学习——模拟用户登录的简单操作
效果截图:
- Spring MVC学习笔记——完整的用户登录
1.搭建环境的第一步是导包,把下面这些包都导入工程中 /media/common/工作/Ubuntu软件/SpringMVC_jar包整理/aop/media/common/工作/Ubuntu软件/S ...
- iOS开发——网络编程OC篇&(二)XMPP实现用户登录与注销
XMPP实现用户登录与注销 登录: 步骤: * 在AppDelegate实现登录 1. 初始化XMPPStream 2. 连接到服务器[传一个JID] 3. 连接到服务成功后,再发送密码授权 4. 授 ...
- 学习MVC之租房网站(六)-用户登录和权限控制
在上一篇<学习MVC之租房网站(五)-权限.角色.用户管理>完成了权限.角色.用户的增删改查,现在将基于前面完成的内容,进行后台用户登录和权限控制功能的开发. 一.用户登录 用户登录涉及到 ...
- sau交流学习社区第三方登陆github--oauth来实现用户登录
sau交流学习社区第三方登陆github--oauth来实现用户登录 最近在丰富nodejsBlog开发的“交流学习社区”(https://www.mwcxs.top)的其他功能以及修复一些bug. ...
- djangorestframework-jwt自带的认证视图进行用户登录验证源代码学习
Django REST framework JWT djangorestframework-jwt自带的认证视图进行用户登录验证源代码学习 SECRET_KEY = '1)q(f8jrz^edwtr2 ...
- Spring学习之SpringMVC框架快速搭建实现用户登录功能
引用自:http://blog.csdn.net/qqhjqs/article/details/41683099?utm_source=tuicool&utm_medium=referral ...
随机推荐
- Azure Automation (1) 入门
<Windows Azure Platform 系列文章目录> 通过Azure Automation(自动化),开发人员可以自动完成通常要在云环境中执行的手动.长时间进行.易出错且重复性高 ...
- JAVA 设计模式 享元模式
用途 享元模式 (Flyweight) 运用共享技术有效地支持大量细粒度的对象. 享元模式是一种结构型模式. 结构
- 基于HTML5 WebGL实现3D飞机叶轮旋转
在上一篇<基于HT for Web矢量实现2D叶轮旋转>中讲述了叶轮旋转在2D拓扑上的应用,今天我们就来讲讲叶轮旋转在3D上的应用. 在3D拓扑上可以创建各种各样的图元,在HT for W ...
- 关于Entity Framework中的Attached报错相关解决方案的总结
关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...
- Shiro —— Spring 环境下的使用
一.使用 1.搭建基础环境 (1)导入 Spring 和 Shiro 的 Jar 包 正常导入 spring jar包 导入日志包 log4j-1.2.15.jar slf4j-api-1.6.1.j ...
- HTML5 input事件检测输入框变化
之前一直用change事件来监听输入框内容是否发生变化,只有当输入框失去焦点时才会触发,没想到html5还有个input事件,只要输入框内容发生变化就会立即触发,既然有这么好的东西我们干嘛放着不用呢, ...
- 认识IoC
第一次接触IoC是我在学习MVP框架的时候,搭建一个MVP框架需要用到IoC,那时候就以为IoC就是依赖注入,但在后来的逐步了解中发现那个只是它的别名而已.IoC全称应该是Inversion of C ...
- Android的px、dp和sp
Android的px.dp和sppx: 即像素,1px代表屏幕上一个物理的像素点:偶尔用到px的情况,是需要画1像素表格线或阴影线的时候. dp: 这个是最常用但也最难理解的尺寸单位.它与“像素密度” ...
- 【Java每日一题】20161116
package Nov2016; public class Ques1116 { public static void main(String[] args){ System.out.println( ...
- Apache+Mod_Python配置
我其实不是个适合做编程的人,因为喜欢折腾,不喜欢日复一日的重复同样的事情.感觉挺适合做网管(运维)的. 经常在摆弄一些小众的程序员不怎么会关心的东西,不走寻常路.有时也挺纠结的,折腾这些东西的过程中, ...