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
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
相关文章推荐
- maven eclipse
- 我与nginx的初次见面
- Linux SSH安装与测试
- 2016-01-07 工作笔记7
- MFC CString to char* (Visual Studio 2015 亲测可用)
- 文字颜色渐变特效
- 黑客们成功地在土豆上安装了 Linux !
- 2016.1.7
- 加密解密技术基础以及公钥基础设施(PKI)
- Scalaz(24)- 泛函数据结构: Tree-数据游览及维护
- Scalaz(24)- 泛函数据结构: Tree-数据游览及维护
- 『原创』统计建模与R软件-第六章 回归分析
- 北京Uber优步司机奖励政策(1月8日)
- 2016-01-06 工作笔记6
- 2165: 大楼 倍增floyd
- 130_Bribe the Prisoners 囚徒贿赂问题 (2009 Round1C C)
- 花开的季节,携梦想归来(一)
- 滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(1月8日)
- Product of Array Except Self
- [leetcode] 143. Reorder List 解题报告