WeChat demo 麦子学院课程笔记 XMPP部分

服务器:

ejabberd:容易安装

open fire:功能强大,安装复杂


安装步骤:

xmpp.org -> xmpp software -> ejabberd -> download -> Mac OS X -> 下载之后双击安装

 -> 若因安全问题无法安装则去settings -> security -> allow apps downloaded from "anywhere"即可 


配置服务器:

安装好后,在application/ejabberd/bin文件夹,点start弹出服务器网页 -> launch -> 输入用户名admin@diana.local密码admin登录

Virtual Host -> Users -> 任意 Add Users -> 每个user里有roster(花名册)-> 通过jabber id 添加好友 -> 配置完成


客户端1

iMessage 添加好友 by jabber


客户端程序

建立XMPP

1. 导入XMPP

Github新版本编译会出现找不到libSimu的错误,如何解决见 http://blog.csdn.net/winer888/article/details/49636451

加桥接头文件 OC->swift

2. 构建管道 xmppStream是连接客户端和服务器的管道

xmppStream = XMPPStream()

        xmppStream?.addDelegate(self, delegateQueue: dispatch_get_main_queue())

登录

1. 登录逻辑

判断是否已登录(本地是否存有用户信息),是则自动登录,否则跳出登录界面,用户手动登录;

根据是否连接成功,是否登录成功(用户名密码是否正确)的代理,用notification通知LoginVC下一步动作,见5

(1)AppDelegate里面:

if NSUserDefaults.standardUserDefaults().stringForKey(USERNAME) != nil { self.login() }

(2)主页FriendListVC,viewDidLoad里面调用:

func checkLogin(){

        let userName = NSUserDefaults.standardUserDefaults().stringForKey(USERNAME)

        if userName == nil{//未登录

            self.navigationController?.pushViewController(LoginViewController(), animated: false)

        }else{//已登录

            let trimmedUserName = userName!.componentsSeparatedByString("@")[0]

            self.lordUser = UserInfo(id: 0, name: trimmedUserName)

        }

}

(3)手动登录在LoginViewController点击登录按钮时

保存用户名和密码到本地,再调用 appDelegate.login()

2. 连接 AppDelegate login()的实现 {

if (xmppStream?.isConnected() == true) { return }

let lordUsername = NSUserDefaults.standardUserDefaults().stringForKey(USERNAME)

let lordPassword = NSUserDefaults.standardUserDefaults().stringForKey(PASSWORD)

if (lordUsername == nil || lordPassword == nil) { return }

xmppStream?.myJID = XMPPJID.jidWithString(lordUsername)

        xmppStream?.hostName = "localhost" //因为服务器就在本机,若服务器在外网,则写其IP地址

do { try xmppStream!.connectWithTimeout(90) }

catch{ print("connect failed."); return }

}

3. 是否登录成功的代理

(1)连接成功 -> 检查用户名密码

func xmppStreamDidConnect(sender: XMPPStream!) {

let lordPassword = NSUserDefaults.standardUserDefaults().stringForKey(PASSWORD)

do { try xmppStream?.authenticateWithPassword(lordPassword) }

catch { print("authentication failed.") } }

(2)-> 用户名密码正确 -> goOnline()

func xmppStreamDidAuthenticate(sender: XMPPStream!) {

        self.goOnline()

NSNotificationCenter.defaultCenter().postNotification(NSNotification(name: LOGINAUTHENTICATE, object: nil)) }

func goOnline(){

let presence = XMPPPresence()

        xmppStream?.sendElement(presence) }

(3)-> 用户名或密码错误

func xmppStream(sender: XMPPStream!, didNotAuthenticate error: DDXMLElement!) {

        NSNotificationCenter.defaultCenter().postNotification(NSNotification(name: LOGINDIDNOTAUTHENTICATE, object: nil)) }

(4)LoginVC 添加observer响应Notification

func loginAuthenticated() { //成功则返回主页,并传值给主页的lordUser变量

        let friendListViewController = self.navigationController?.viewControllers[0] as! FriendListViewController

friendListViewController.lordUser = UserInfo(id: 0, name: trimmedUserName!)

self.navigationController?.popToViewController(friendListViewController, animated: false) }

func loginDidNotAuthenticate() //失败则给出提示

{ errorTip?.text = "用户名或密码错误" }

接收消息

1. 通信机制

NSNotification 或 自定义delegate 都可以解决通信问题,感觉notification逻辑更简单清晰 便于理解,参数通过object传递,

但苹果推荐关于UI的东西用delegate,和效率有关。

2. 状态消息 & 聊天消息

(1)protocol PresenceDelegate { func presneceChanged(friend: UserInfo) }

protocol MessageDelegate { func didReceiveMessage(messageInfo: MessageInfo) }

(2)AppDelegate 里声明变量

var presenceDelegate: PresenceDelegate?

var messageDelegate: MessageDelegate?

(3)AppDelegate XMPP代理 调用above two代理函数

func xmppStream(sender: XMPPStream!, didReceivePresence presence: XMPPPresence!) {

        if (sender.myJID.user != presence.from().user){ //有几个好友就调用几次

            let friend = UserInfo(id: 1, name: presence.from().user) //user为截去域名后的name部分

            self.presenceDelegate?.presneceChanged(friend) } }

func xmppStream(sender: XMPPStream!, didReceiveMessage message: XMPPMessage!) {

if message.isChatMessage() {//还有可能是语音图片消息

let senderName = message.from().user

let targetName = message.to().user

let sender = UserInfo(id: 1, name: senderName)

let target = UserInfo(id: 0, name: targetName)

if let messageBody = message.body(){

let messageInfo = MessageInfo(id: 0, body: messageBody, sender: sender, target: target)

self.messageDelegate?.didReceiveMessage(messageInfo) } } }

(4)继承以上两个Delegate:需要响应朋友变化(FriendListVC),需要响应消息变化(FriendListVC,ChatRoomVC

(5)连接appDelegate和VC

appDelegate.presenceDelegate = self

        appDelegate.messageDelegate = self

(6)FriendListVC实现代理函数

func presneceChanged(friend: UserInfo) {

for user in self.friendListDataSource{

if (user.name == friend.name) { self.friendListDataSource.removeObject(user) } }

self.friendListDataSource.insertObject(friend, atIndex: 0)

self.friendListTableView.reloadData() }

(7)ChatRoomVC实现代理函数

func didReceiveMessage(messageInfo: MessageInfo) {

        if messageInfo.sender?.name == self.friendUser?.name {

            //商业项目需要更新message ID, ejabberd并不需要

            let lastID = (self.messageDataSource.lastObject as! MessageInfo).messageId! as Int

            let IdUpdatedMsg = MessageInfo(id: lastID+1, body: messageInfo.messageBody!, sender: messageInfo.sender!, target: messageInfo.target!)

            self.messageDataSource.addObject(IdUpdatedMsg)

self.messageTableView.reloadData()


            let indexPath = NSIndexPath(forRow: messageDataSource.count-1, inSection: 0)

            messageTableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)

        }

    }

登出

1. 调用 appDelegate.disconnect()

{ let presence = XMPPPresence.elementWithName("unavailable")

xmppStream.sendElement(presence)

xmppStream.didconnect() }

2. 清楚用户信息

NSUserDefaults.standard...().remove...(USERNAME)

NSUserDefaults.standard...().remove...(USERNAME)

NSUserDefaults.standard...().syncronize()

3. 重新登录要返回到主页面

appDelegate.tabbarController.selectedIndex = 0





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值