Swift使用XMPPFramework做IM即时通信的Demo
一篇文章处理了文本中表情的替换,现在来完成消息的发送功能吧(貌似前后并没有逻辑关系哈)
首先为了测试,我们需要下载spark工具,它可以连接openfire搭建的后台来完成即时通信的功能,方便测试。
下载地址点这儿
博主这里用的是Spark 2.8.3,各位可以根据自己所使用的平台不同选择对应的客户端下载。由于目前只是做移动端开发,所以后台的搭建各位可以自行google。
使用Swift连接openfire服务端,可以使用XMPPFramework框架(同android端的smack类似)。大家可以选择手动导入,也可以使用cocoapod导入。博主懒,就用了cocoapod
现在的XMPPFramework已经支持了Swift,所以只需在要使用的controller中导入即可,不需要再建立桥接文件了。
import XMPPFramework
- 1
准备工作都做得差不多了,接下来就开始真正的工作吧。
连接服务器
/// xmpp流
var xmppStream: XMPPStream!
- 1
- 2
/// 连接服务器
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)
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
因为我们这里设置了代理,所以控制器需要遵循XMPPStreamDelegate协议
在连接成功后会调用回调方法
/// 连接服务器的回调
func xmppStream(_ sender: XMPPStream!, socketDidConnect socket: GCDAsyncSocket!) {
print("连接成功")
}
- 1
- 2
- 3
- 4
登陆
我们还可以在回调方法中输入密码来登陆账号
/// 连接成功后使用密码登陆
func xmppStreamDidConnect(_ sender: XMPPStream!) {
print("ok")
do {
try sender.authenticate(withPassword: 密码)
} catch let error {
print(error)
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
当登陆成功后,会调用登陆成功的回调方法,我们可以在登陆成功的回调方法中设置登陆状态
/// 用户登陆成功
func xmppStreamDidAuthenticate(_ sender: XMPPStream!) {
print("登陆成功")
let presence = XMPPPresence(type: "available")
xmppStream.send(presence)
}
- 1
- 2
- 3
- 4
- 5
- 6
用户的登陆状态分别有以下几种:
available 上线
away 离开
do not disturb 忙碌
unavailable 下线
退出
既然有登陆,那我们就需要实现退出功能
/// 退出登陆并断开连接
@objc func disconnect() {
let presence = XMPPPresence(type: "unavailable")
xmppStream.send(presence)
///断开连接
xmppStream.disconnect()
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
设置退出很简单,我们只需要把状态设置为下线即可,大家也可以不用在这个方法中设置断开连接,毕竟我们有时退出是为了更换账号呢(这里只是为了方便演示)
同样,退出也有回调方法
/// 退出登陆的回调
func xmppStreamDidDisconnect(_ sender: XMPPStream!, withError error: Error!) {
print("退出成功")
}
- 1
- 2
- 3
- 4
接收消息
有了登陆和退出功能,现在就是消息的接收和发送了,因为接收消息比较简单,所以我们就先说明接收消息的方法吧。
/// 成功接收消息
func xmppStream(_ sender: XMPPStream!, didReceive message: XMPPMessage!) {
let text = message.body()
if text != nil {
label.text = text
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
接收的消息默认都存在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)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
在成功发送消息之后,同样也有一个回调方法
/// 成功发送消息
func xmppStream(_ sender: XMPPStream!, didSend message: XMPPMessage!) {
print("成功发送消息 \(message.body())")
}
- 1
- 2
- 3
- 4
对了,到此就完成了一个最最简单的使用基于openfire的XMPPFramework框架的IM即时通信功能了。
如果还想了解更多,可以欣赏一下这位CSDN小伙伴写的文章
最后,还是贴一下演示效果和所有的代码吧
在这里呢,博主随便搭了一个简单的界面来演示效果(最上的label显示接收到的消息,左边的发送按钮发送消息–每次都是发送hello,右边的退出按钮退出登录并断开连接)
这里是所有的代码
import UIKit
import XMPPFramework
class 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())")
}
}