本文共 6808 字,大约阅读时间需要 22 分钟。
一篇文章处理了文本中表情的替换,现在来完成消息的发送功能吧(貌似前后并没有逻辑关系哈)
首先为了测试,我们需要下载spark工具,它可以连接openfire搭建的后台来完成即时通信的功能,方便测试。
博主这里用的是Spark 2.8.3,各位可以根据自己所使用的平台不同选择对应的客户端下载。由于目前只是做移动端开发,所以后台的搭建各位可以自行google。使用Swift连接openfire服务端,可以使用XMPPFramework框架(同android端的smack类似)。大家可以选择手动导入,也可以使用cocoapod导入。博主懒,就用了cocoapod
现在的XMPPFramework已经支持了Swift,所以只需在要使用的controller中导入即可,不需要再建立桥接文件了。
import XMPPFramework
准备工作都做得差不多了,接下来就开始真正的工作吧。
/// xmpp流var xmppStream: XMPPStream!
/// 连接服务器func connect() { if xmppStream == nil { xmppStream = XMPPStream() /// 设置代理 xmppStream.addDelegate(self, delegateQueue: DispatchQueue.main) } if !xmppStream.isConnected() { //用户名 let username = "ave2" /// 初始化一个jid,resource可以为空 let jid = XMPPJID(user: username, domain: 域名, resource: nil) xmppStream.myJID = jid do { /// 连接服务器 try xmppStream.connect(withTimeout: 5) } catch let error { print(error) } }}
因为我们这里设置了代理,所以控制器需要遵循XMPPStreamDelegate协议
在连接成功后会调用回调方法/// 连接服务器的回调func xmppStream(_ sender: XMPPStream!, socketDidConnect socket: GCDAsyncSocket!) { print("连接成功")}
我们还可以在回调方法中输入密码来登陆账号
/// 连接成功后使用密码登陆func xmppStreamDidConnect(_ sender: XMPPStream!) { print("ok") do { try sender.authenticate(withPassword: 密码) } catch let error { print(error) }}
当登陆成功后,会调用登陆成功的回调方法,我们可以在登陆成功的回调方法中设置登陆状态
/// 用户登陆成功func xmppStreamDidAuthenticate(_ sender: XMPPStream!) { print("登陆成功") let presence = XMPPPresence(type: "available") xmppStream.send(presence)}
用户的登陆状态分别有以下几种:
available 上线 away 离开 do not disturb 忙碌 unavailable 下线既然有登陆,那我们就需要实现退出功能
/// 退出登陆并断开连接@objc func disconnect() { let presence = XMPPPresence(type: "unavailable") xmppStream.send(presence) ///断开连接 xmppStream.disconnect()}
设置退出很简单,我们只需要把状态设置为下线即可,大家也可以不用在这个方法中设置断开连接,毕竟我们有时退出是为了更换账号呢(这里只是为了方便演示)
同样,退出也有回调方法/// 退出登陆的回调func xmppStreamDidDisconnect(_ sender: XMPPStream!, withError error: Error!) { print("退出成功")}
有了登陆和退出功能,现在就是消息的接收和发送了,因为接收消息比较简单,所以我们就先说明接收消息的方法吧。
/// 成功接收消息func xmppStream(_ sender: XMPPStream!, didReceive message: XMPPMessage!) { let text = message.body() if text != nil { label.text = text }}
接收的消息默认都存在message的body方法当中,我们只需要取出,然后对其进行相应的操作即可。奇怪的是,发送一条消息,这个接收消息的回调方法会调用三次,第一次和第三次会输出nil,只有第二次输出的才是有消息的内容,各位可以尝试打印输出。
最后来实现发送消息吧,
因为发送消息需要指定发送的对象,我们这里就指定私聊的名为ave1的用户吧/// 发送消息@objc func send() { print("发送消息") ///创建目的用户的jid let jid = XMPPJID(user: "ave1", domain: 域名, resource: nil) ///创建消息 let message = XMPPMessage(type: "chat", to: jid) ///添加消息内容 message?.addBody("hello") ///发送消息 xmppStream.send(message)}
在成功发送消息之后,同样也有一个回调方法
/// 成功发送消息func xmppStream(_ sender: XMPPStream!, didSend message: XMPPMessage!) { print("成功发送消息 \(message.body())")}
对了,到此就完成了一个最最简单的使用基于openfire的XMPPFramework框架的IM即时通信功能了。
如果还想了解更多,可以欣赏一下最后,还是贴一下演示效果和所有的代码吧
在这里呢,博主随便搭了一个简单的界面来演示效果(最上的label显示接收到的消息,左边的发送按钮发送消息–每次都是发送hello,右边的退出按钮退出登录并断开连接)
import UIKitimport XMPPFrameworkclass ViewController: UIViewController { /// 接收消息的标签 var label: UILabel! /// xmpp流 var xmppStream: XMPPStream! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. setup() connect() } /// 连接服务器 func connect() { if xmppStream == nil { xmppStream = XMPPStream() /// 设置代理 xmppStream.addDelegate(self, delegateQueue: DispatchQueue.main) } if !xmppStream.isConnected() { //用户名 let username = "ave2" /// 初始化一个jid,resource可以为空 let jid = XMPPJID(user: username, domain: 域名, resource: nil) xmppStream.myJID = jid do { /// 连接服务器 try xmppStream.connect(withTimeout: 5) } catch let error { print(error) } } } /// 退出登陆并断开连接 @objc func disconnect() { let presence = XMPPPresence(type: "unavailable") xmppStream.send(presence) xmppStream.disconnect() } /// 构建界面 func setup() { label = UILabel(frame: CGRect(x: 100, y: 50, width: 200, height: 500)) label.textColor = UIColor.black label.text = "hello" label.textAlignment = .center label.layer.borderWidth = 1 label.numberOfLines = 0 self.view.addSubview(label) let button = UIButton(frame: CGRect(x: 100, y: 600, width: 90, height: 44)) button.setTitle("发送", for: .normal) button.setTitleColor(UIColor.black, for: .normal) button.layer.borderWidth = 1 button.addTarget(self, action: #selector(send), for: .touchUpInside) self.view.addSubview(button) let button1 = UIButton(frame: CGRect(x: 210, y: 600, width: 90, height: 44)) button1.setTitle("退出", for: .normal) button1.setTitleColor(UIColor.black, for: .normal) button1.layer.borderWidth = 1 button1.addTarget(self, action: #selector(disconnect), for: .touchUpInside) self.view.addSubview(button1) } /// 发送消息 @objc func send() { print("发送消息") ///创建目的用户的jid let jid = XMPPJID(user: "ave1", domain: 域名, resource: nil) ///创建消息 let message = XMPPMessage(type: "chat", to: jid) ///添加消息内容 message?.addBody("hello") ///发送消息 xmppStream.send(message) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. }}extension ViewController: XMPPStreamDelegate { /// 连接服务器的回调 func xmppStream(_ sender: XMPPStream!, socketDidConnect socket: GCDAsyncSocket!) { print("连接成功") } /// 连接成功后使用密码登陆 func xmppStreamDidConnect(_ sender: XMPPStream!) { print("ok") do { try sender.authenticate(withPassword: 密码) } catch let error { print(error) } } /// 用户登陆成功 func xmppStreamDidAuthenticate(_ sender: XMPPStream!) { print("登陆成功") let presence = XMPPPresence(type: "available") xmppStream.send(presence) } /// 退出登陆的回调 func xmppStreamDidDisconnect(_ sender: XMPPStream!, withError error: Error!) { print("退出成功") } /// 成功接收消息 func xmppStream(_ sender: XMPPStream!, didReceive message: XMPPMessage!) { let text = message.body() if text != nil { label.text = text } } /// 成功发送消息 func xmppStream(_ sender: XMPPStream!, didSend message: XMPPMessage!) { print("成功发送消息 \(message.body())") }}