7. Swift 基于Xmpp和openfire实现一个简单的登录注册
1. 基本步骤:首先导入Xmpp框架,配置环境
-》由于我们使用的是OC的Xmpp框架,再进行Swift开发时需要进行桥接。 具体方法就是创建一个基于c的.h的头文件,然后将我们需要编译OC的语言的头文件包含这个.h文件中;
-》然后导入如下库文件,在头头文件选择路径中
如上图, 设置header Search paths 设置头文件的搜索路径,导入libxml2库文件相对路径,***注意前面是 usr 。以前第一次装的时候写成user找了半个多小时
-> 然后创建界面,随便弄两个框框和按钮自定义一个建议的界面。
应为在应用程序中用户名和密码可能被反复的使用,所以我们需要讲它门设置成一个单利类。
如下代码所示:
import UIKit
class WSBUserinfo: NSObject {
// 登录的用户名密码
var userName : String?
var userPasswd : String?
// 注册的用户名密码
var userRegisterName : String?
var userRegisterPasswd : String?
// 为了区分登录和注册
var isLogin : Bool?
// 单例
class func getShareInstance() -> WSBUserinfo{
struct Singleton {
static var dispatchOne : dispatch_once_t = 0
static var instance : WSBUserinfo? = nil
}
dispatch_once(&Singleton.dispatchOne) { () -> Void in
Singleton.instance = WSBUserinfo()
}
return Singleton.instance!
}
}
//由于登录流程设计到了xmpp流协议实现,步骤较多。这里我们可以单独封装一个工具类。这样我们的登录和注册的主控制器就能得到极大的解脱:
在登录控制器中我们只需要将输入框的用户输入信息赋值到单利用户信息类 UserInfo里
然后调用 单利工具类的 usrLogin()方法及可自动完成所有的登录流程
再通过指定一个协议,实现对登录和注册状态的监听;
注册控制器的逻辑同上,这里就不重复了 。
注意点1:再每次连接请求时先把之前的连接断开,这样能避免一个账号长连接而其它的账号无法连接。
注意点2:再发送登录注册时中间都涉及到了共同的连接请求和连接状态请求,我们需要在单利类中建立一个Bool属性值做分支判定,这样我们只需要在方法内部做简单的调整,从而省去大量的代码步骤。
具体步骤请看下面代码
import UIKit
class WSBLoginViewController: UIViewController,WSBXMPPLoginDelegate {
@IBOutlet weak var userNameField: UITextField!
@IBOutlet weak var userPasswdField: UITextField!
@IBAction func loginBtnClick(sender: AnyObject) {
WSBUserinfo.getShareInstance().isLogin = true
print("用户名:\(userNameField.text!)")d
print("密码是:\(userPasswdField.text!)")
// 把用户名 密码存入工具类 WSBUserinfo 这个单例对象中
WSBUserinfo.getShareInstance().userName = userNameField.text!
WSBUserinfo.getShareInstance().userPasswd = userPasswdField.text!
// 调用XMPP 工具类 完成登录
// 登录之前先给WSBXMPPTool设置代理
WSBXMPPTool.getSharedInstance().loginDelegate = self
WSBXMPPTool.getSharedInstance().userLogin()
}
/** 登录协议中的方法 */
func loginSuccess() {
print("登录成功")
// 切换到主界面
let storyBoard = UIStoryboard.init(name: "Main", bundle: nil)
UIApplication.sharedApplication().keyWindow?.rootViewController =
storyBoard.instantiateInitialViewController()
}
func loginFailed() {
print("登录失败")
}
func loginNetError() {
print("登录时网络错误")
}
override func viewDidLoad() {
super.viewDidLoad()
}
deinit{
print("deinit\(self)")
}
}
RegisterViewController:
import UIKit
class WSBRegisterViewController: UIViewController,WSBXMPPRegisterDelegate {
@IBOutlet weak var userRegiserName: UITextField!
@IBOutlet weak var userRegisterPasswd: UITextField!
@IBAction func registerBtnClick(sender: AnyObject) {
// 说明这是注册行为
WSBUserinfo.getShareInstance().isLogin = false
WSBUserinfo.getShareInstance().userRegisterName = self.userRegiserName.text!
WSBUserinfo.getShareInstance().userRegisterPasswd = self.userRegisterPasswd.text!
// 调用XMPPTool的 注册方法
WSBXMPPTool.getSharedInstance().registerDelegate = self
WSBXMPPTool.getSharedInstance().userRegister()
}
/** 实现注册协议中的方法 */
func registerSuccess() {
print("注册成功")
self.dismissViewControllerAnimated(true, completion: nil)
}
func registerFailed() {
print("注册失败")
}
func registerNetError() {
print("注册时网络错误")
}
}
登录和注册协议
import Foundation
// 登录协议
protocol WSBXMPPLoginDelegate : NSObjectProtocol {
// 登录成功
func loginSuccess()
// 登录失败
func loginFailed()
// 网络错误
func loginNetError()
}
// 注册协议
protocol WSBXMPPRegisterDelegate : NSObjectProtocol {
// 注册成功
func registerSuccess()
// 注册失败
func registerFailed()
// 注册网络错误
func registerNetError()
}
Swift:
import UIKit
/** 桥接文件 项目--buildSettings --> 搜索 Objective-c Bride 设置即可
这是一个XMPP的工具类 可以完成登录和注册的行
*/
class WSBXMPPTool: NSObject, XMPPStreamDelegate {
var xmppStream : XMPPStream!
// 登录的Delegate
weak var loginDelegate : WSBXMPPLoginDelegate?
// 注册的Deletegate
weak var registerDelegate : WSBXMPPRegisterDelegate?
// 保证xmppStream 使用时非空
override init() {
super.init()
setupXmppStream()
}
class func getSharedInstance() -> WSBXMPPTool {
struct Singleton {
static var predicate : dispatch_once_t = 0
static var instance : WSBXMPPTool? = nil
}
dispatch_once(&Singleton.predicate) { () -> Void in
Singleton.instance = WSBXMPPTool()
}
return Singleton.instance!
}
// 设置流 设置代理
func setupXmppStream(){
xmppStream = XMPPStream()
xmppStream.addDelegate(self, delegateQueue: dispatch_get_main_queue())
}
// 连接服务器
func connectToHost(){
// 先断开上次的 不断开登录之后没法再登录
xmppStream.disconnect();
// 调用设置xmppStream
if self.xmppStream == nil {
self.setupXmppStream()
}
var userName : String? = nil
if WSBUserinfo.getShareInstance().isLogin! {
userName = WSBUserinfo.getShareInstance().userName
}else{
userName = WSBUserinfo.getShareInstance().userRegisterName
}
// 构建jid 设置hostName 和 port
xmppStream.myJID = XMPPJID.jidWithUser(userName, domain: XMPPDOMAIN, resource: "iphone")
xmppStream.hostName = XMPPHOSTNAME
xmppStream.hostPort = XMPPPORT
do {
try xmppStream.connectWithTimeout(XMPPStreamTimeoutNone)
}catch let error as NSError{
print(error.description)
}
}
// 连接成功(代理方法)
func xmppStreamDidConnect(sender: XMPPStream!) {
// 调用发送密码 请求授权
if WSBUserinfo.getShareInstance().isLogin!{
self.sendLoginPasswd()
}else{
// 使用密码注册
self.sendRegisterPasswd()
}
}
// 发送密码 注册
func sendRegisterPasswd(){
do{
try xmppStream.registerWithPassword(WSBUserinfo.getShareInstance().userRegisterPasswd)
}catch let error as NSError{
print(error.description)
}
}
// 发送密码 请求授权
func sendLoginPasswd(){
do{
try xmppStream.authenticateWithPassword(WSBUserinfo.getShareInstance().userPasswd)
}catch let error as NSError{
print(error.description)
}
}
// 授权成功(代理方法)
func xmppStreamDidAuthenticate(sender: XMPPStream!) {
print("授权成功")
// 发送在线消息
self.sendOnLine()
// 调用代理的登录成功的方法
loginDelegate?.loginSuccess()
}
// 发送在线消息
func sendOnLine(){
xmppStream.sendElement(XMPPPresence())
}
// 授权失败
func xmppStream(sender: XMPPStream!, didNotAuthenticate error: DDXMLElement!) {
print(error.description)
// 授权失败 调用代理的登录失败的方法
loginDelegate?.loginFailed()
}
// 连接断开(代理方法)
func xmppStreamDidDisconnect(sender: XMPPStream!, withError error: NSError!) {
// 如果网络有问题断开 则error 中有值
// 如果是主动断开 则error是 nil
if error != nil {
if WSBUserinfo.getShareInstance().isLogin!{
//登录网络有问题 调用代理的网络错误
loginDelegate?.loginNetError()
}else{
// 注册时网络有问题
registerDelegate?.registerNetError()
}
}
}
//注册成功 (代理方法 )
func xmppStreamDidRegister(sender: XMPPStream!) {
// 调用代理的注册成功
registerDelegate?.registerSuccess()
}
// 注册失败 (代理方法 )
func xmppStream(sender: XMPPStream!, didNotRegister error: DDXMLElement!) {
registerDelegate?.registerFailed()
}
// 用户完成登录的方法
func userLogin(){
self.connectToHost()
}
// 用户完成注册的方法
func userRegister(){
self.connectToHost()
}
}
总的来说基本思路和OC的写法基本相同,下面简但介绍下程序的设计思路。
一 总体登录流程:
1.设置xmpp流配置(port id domain)-》2. 请求链接绑定jid-》3.监听链接是否成功-》4.成功则发送密码请求授权-》5.监听授权是成功-》6.授权成功则发送出席状态。
注册流程:
1.设置xmpp流配置(port id domain)-》 2.请求链接绑定jid-》3.监听链接是否成功-》4.成功则发送密码请求注册-》5.监听注册是否成功-》6.注册成功则返回登录界面。
从上面可以看出登录和注册的基本流程大致相同,只不郭仔第4步骤中调用的方法不通而已,为了操作方便我们定义了一个Bool值,在第3部链接成功中进行选择判定 isRegister。
其余对应的方法不通的地方也依次使用Bool选择判定。
二 .协议的使用时机。
我们将此6部只需要封装到一个方法里,并返回一个结果(链接是否成功,授权是否成功) usrLogin:(返回的结果)。 这样我们在主控制器中通过调用xmppTool单利类的方法就能够拿到这个结果。
在上面链接是否成功,是否授权,是否注册成功,一共5处需传递给主控制器。 这里可以使用协议或者代理,当然还有通知.
下面就种方式常用的方式代理和闭包(其实就相当于OC的Block回调,变了个说法而已)
****协议的写法和OC大不相同,值得注意的是,我们定义的协议前面一定要继承系统的NSObjectProtocol(这是因为我们在定义var delegate:Protococl! 的时候,前面不能使用weak,但是不使用weak又会导致设置协议后造成另一个对象强强引用释放不了,所以此处需要继承下系统的协议,具体什么原因楼主目前暂时也还没有弄明白)。
其它的只是变了个写法格式,看代码就可以了,逻辑完全没变。
三. 使用Block代替上面的协议。
3.1 这里我们首先定义一个枚举类型,用于定义回调传值的类型,然后再定义一个闭包类型。
enum XMPPResultType{
case XMPPResultTypeRegisterSuccess,
XMPPResultTypeRegisterFailed,
XMPPResultTypeRegisterNetError
}
typealias RegisterCloserType = (result : XMPPResultType) -> Void
3.2 接着在XmppTool工具类中定义一个闭包类型,用来接收注册或者登陆控制器中传来的闭包函数
weak var loginDelegate : WSBXMPPLoginDelegate?
// 保存传入的闭包
var registerCloser : RegisterCloserType!
3.3 调用闭包方法
/* 用户完成注册的方法 当用闭包时 需要让调用者传入一个闭包来获取注册状态 */
func userRegister(function : RegisterCloserType!){
registerCloser = function
self.connectToHost()
}
3.4在XmppTool工具类中需要使用回调的地方执行次闭包函数,下面以其中一个为例, 网络连接错误,注册成功,失败,这三处都需要调用。
registerCloser!(result: XMPPResultType.XMPPResultTypeRegisterSuccess)
3.5 我们在主控制器中只需要拿出闭包函数的result的状态及可判断是否 后台执行的结果.注意需要使用weakself,否则无法释放。
weak var weakVc = self
WSBXMPPTool.getSharedInstance().userRegister { (result) -> Void in
switch result{
case .XMPPResultTypeRegisterSuccess:
print("注册成功")
weakVc?.dismissViewControllerAnimated(true, completion: nil)
case .XMPPResultTypeRegisterFailed:
print("注册失败")
case .XMPPResultTypeRegisterNetError:
print("网络错误")
} } }
7. Swift 基于Xmpp和openfire实现一个简单的登录注册的更多相关文章
- go语言实现一个简单的登录注册web小程序
最近学习golang也有一段时间了,基础差不多学了个大概,因为本人是java程序员,所以对web更感兴趣.根据<go web编程>中的例子改编一个更简单的例子,供新手参考,废话不多说,上菜 ...
- Android基于XMPP Smack openfire 开发的聊天室
Android基于XMPP Smack openfire 开发的聊天室(一)[会议服务.聊天室列表.加入] http://blog.csdn.net/lnb333666/article/details ...
- (转)微服务_创建一个简单的Eureka注册中心
原文地址:https://www.cnblogs.com/lplshermie/p/9105329.html 微服务和分布式已经成了一种极其普遍的技术,为了跟上时代的步伐,最近开始着手学习Spring ...
- 创建一个简单的Eureka注册中心
微服务和分布式已经成了一种极其普遍的技术,为了跟上时代的步伐,最近开始着手学习SpringCloud,就从Eureka开始.他们俩就不做介绍了,网上的说明一堆,随便打开一个搜索引擎输入关键字都足够了解 ...
- 基于Spring aop写的一个简单的耗时监控
前言:毕业后应该有一两年没有好好的更新博客了,回头看看自己这一年,似乎少了太多的沉淀了.让自己做一个爱分享的人,好的知识点拿出来和大家一起分享,一起学习. 背景: 在做项目的时候,大家肯定都遇到对一些 ...
- 基于gin框架搭建的一个简单的web服务
刚把go编程基础知识学习完了,学习的时间很短,可能还有的没有完全吸收.不过还是在项目中发现知识,然后在去回顾已学的知识,现在利用gin这个web框架做一个简单的CRUD操作. 1.Go Web框架的技 ...
- 基于 Vue + Koa2 + MongoDB + Redis 实现一个完整的登录注册
项目地址:https://github.com/caochangkui/vue-element-responsive-demo/tree/login-register 通过 vue-cli3.0 + ...
- javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册
一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp ...
- jmeter 压力测试(一)一个简单的登录
写在最前面,之所以记录这个最最简单的http的登录,是因为捣鼓了一天,真的是找错也找不错了,后来请教的同事,重新写了一个ok了,最后发现竟然是因为[http信息头]写的有问题,简直是!!醉了 如下,这 ...
随机推荐
- 任务9user表建表语句
create table user( id int not null auto_increment primary key, username ) not null default '', pwd ) ...
- k8s入门系列之guestbook快速部署
k8s集群以及一些扩展插件已经安装完毕,本篇文章介绍一下如何在k8s集群上快速部署guestbook应用. •实验环境为集群:master(1)+node(4),详细内容参考<k8s入门系列之集 ...
- randow()方法
Math库里的static(静态)方法random(),该方法的作用是产生0和1之间的一个double值. 注意产生的值包括0不包括1.
- jqurey datatable mRender FnRender 不起作用问题
用这个插件的 知道他不起作用,就应该知道他是做什么的了吧,我的不起作用的原因是版本的问题 我在网上查找的用法 是 "fnRender":fuction(obj){} 可是不起作 ...
- mac系统terminal连接linux
ssh user@hostname user是管理员账号 hostname是服务器ip
- No Spring WebApplicationInitializer types detected on classpath。启动时不报错,但是页面打不开。
一片红,没有黑色disPatcher的加载. 百度,但是没有用,二十分钟浪费,这个问题的本质就是web.xml中的disPatcher没有加载,但是我肯定和代码无关,配置文件也没有变化过,值可能是to ...
- iOS开发:(线程篇-上)线程和进程
iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...
- mysql 设置max_allowed_packet 大小的办法
show VARIABLES like '%max_allowed_packet%'; 第一句是查询 max_allowed_packet 的大小,第二句是重新设定 max_allowe ...
- 日常开发使用GIT命令
git是一种分布式的版本管理工具,现在我总结下日常使用的git命令 1)检出 git clone 地址 --检出代码 #这里的地址是代码池的地址,如Github或bitbucket 2)增加文件 gi ...
- 非常强大的table根据表头排序,点击表头名称,对其内容排序
js代码: /** * 通过表头对表列进行排序 * * @param sTableID * 要处理的表ID<table id=''> * @param iCol * 字段列id eg: 0 ...