您的位置:首页 > 其它

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

2016-01-08 08:36 232 查看
服务器:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: