实现收发消息
本文将指导你如何利用 RTM Swift SDK 构建简单的应用程序,内容涵盖了集成和开发的基础知识:开通声网账号、获取 SDK、发送消息、接收消息等。
准备工作
开始构建项目前,你需要完成开通服务,并检查你的浏览器是否满足平台支持中的最低版本要求。
构建项目
1. 项目配置
根据以下步骤配置你的项目:
-
在 Xcode 中创建一个 iOS 平台下的 Single View App,项目设置如下:
- Product Name 设为
RtmQuickstart
。 - Organization Identifier 设为
agora
。 - User Interface 选择 Storyboard。
- Language 选择 Swift。
- Product Name 设为
-
通过以下任意一种方式获取最新的 RTM Swift SDK 并导入你的项目。
- 使用 CDN
- 使用 Cocoapods
- 点击此处下载最新版本的 Objective-C SDK。
- 复制 SDK 包中
/libs
路径下所有的xcframework
文件至项目路径下。 - 打开 Xcode,进入 TARGETS > Project Name > General > Frameworks, Libraries, and Embedded Content 菜单。
- 点击 + > Add Other… > Add Files 添加所有的
xcframework
文件,并确保添加的动态库 Embed 属性设置为 Embed & Sign。
添加完成后,项目会自动链接所需系统库。
-
开始前请确保你已安装 Cocoapods,如尚未安装 Cocoapods,参考 Getting Started with CocoaPods 安装说明。
-
在终端里进入项目根目录,并运行
pod init
命令。项目文件夹下会生成一个Podfile
文本文件。 -
打开
Podfile
文件,修改文件为如下内容。注意将Your App
替换为你的 Target 名称。Rubyplatform :ios, '11.0'
target 'Your App' do
# 将 x.y.z 替换为具体的 SDK 版本号,如 2.2.0
# 可通过发版说明获取最新版本号
# 当前示例仅适用于 2.2.0 及之后版本
# 如需获取 2.2.0 之前的版本,请将包名修改为 AgoraRtm_iOS
pod 'AgoraRtm', 'x.y.z'
# 如果你使用的是 2.2.2 或之后版本的 RTM SDK,且项目中同时使用了 RTC SDK v4.3.0 或以上版本
# pod 'AgoraRtm', 'x.y.z', :subspecs => ['RtmKit']
end -
在终端内运行
pod install
命令安装声网 SDK。成功安装后,Terminal 中会显示Pod installation complete!
。 -
成功安装后,项目文件夹下会生成一个后缀为
.xcworkspace
的文件,通过 Xcode 打开该文件进行后续操作。
信息如果你同时集成了 2.2.0 及以上版本的 RTM SDK 和 4.3.0 及以上版本的 RTC SDK,请参考 FAQ 处理集成问题。
2. 初始化 RTM
调用 RTM SDK 的任何 API 之前,需要先创建一个 AgoraRtmClientKit
对象实例,再初始化该实例。在 ContentView.swift
文件中,添加以下代码作为程序模版。你会发现此程序并不完整,不用紧张,我们在后续步骤中将一步步指导你补充完善代码。
你需要将示例中的 <#YOUR APPID#>
字段替换成你项目的 App ID。
import SwiftUI
import Combine
import AgoraRtmKit
struct Message: Identifiable, Equatable {
let id = UUID()
let content: String
}
class ChatViewModel: NSObject, ObservableObject, AgoraRtmClientDelegate{
// Initialize the AgoraRtmClientKit instance
var appid: String = <#YOUR APPID#>
var rtmKit: AgoraRtmClientKit? = nil
@Published var username: String = ""
@Published var message: String = ""
@Published var channel: String = ""
@Published var messages: [Message] = []
// Add the event listener
// Log in the RTM server
// Log out from the RTM server
// Subscribe to a channel
// Unsubscribe from a channel
// Publish a message
}
// Set user interface
struct ContentView: View {
@StateObject private var viewModel = ChatViewModel()
var body: some View {
VStack {
TextField("input user name", text: $viewModel.username)
.padding()
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.title)
HStack {
Button(action: viewModel.login) {
Text("login")
.font(.title)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
Button(action: viewModel.logout) {
Text("logout")
.font(.title)
.padding()
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(10)
}
}
TextField("channel name", text: $viewModel.channel)
.padding()
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.title)
HStack {
Button(action: viewModel.subscribe) {
Text("subscribe")
.font(.title)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
Button(action: viewModel.unsubscribe) {
Text("unsubscribe")
.font(.title)
.padding()
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(10)
}
}
TextField("input message", text: $viewModel.message)
.padding()
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.title)
Button(action: viewModel.sendMessage) {
Text("send")
.font(.title)
.padding()
.background(Color.green)
.foregroundColor(.white)
.cornerRadius(10)
}
// display log
ScrollViewReader { scrollProxy in
List(viewModel.messages) { message in
Text(message.content)
.id(message.id)
}
.onChange(of: viewModel.messages) { _ in
if let lastMessage = viewModel.messages.last {
withAnimation {
scrollProxy.scrollTo(lastMessage.id, anchor: .bottom)
}
}
}
}
.padding()
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
如需了解更多初始化的信息,查看初始配置。
3. 添加事件监听
事件监听程序帮助你实现频道中消息、事件到达后的处理逻辑,添加以下代码到你的程序中以显示收到的消息或事件通知:
// Paste the following code snippet below "Add the event listener" comment
func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveLinkStateEvent event: AgoraRtmLinkStateEvent) {
addToMessageList(str: "RTM link state change current state is: \(event.currentState.rawValue) previous state is :\(event.previousState.rawValue)")
}
func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveMessageEvent event: AgoraRtmMessageEvent) {
addToMessageList(str: "Message received.\n channel: \(event.channelName), publisher: \(event.publisher), message content: \(event.message.stringData!)")
}
4. 登录服务
你需要执行登录操作才能建立与 RTM 服务器的连接,然后才能调用 SDK 的其他 API。将以下代码添加到程序中:
// Paste the following code snippet below "Log in the RTM server" comment
func login() {
if rtmKit != nil {
addToMessageList(str: "RTM alreay login! Logout first!")
return
}
let config = AgoraRtmClientConfig(appId: appid, userId: username);
rtmKit = try! AgoraRtmClientKit(config, delegate: self)
rtmKit?.login(appid, completion: { response, error in
if error != nil {
self.addToMessageList(str: "login failed error code is \(error?.errorCode.rawValue), reason is \(error?.reason)")
} else {
self.addToMessageList(str: "\(self.username) login succsss")
}
})
}
5. 收发消息
调用 publish
方法向 Message Channel 发送消息后,RTM 会把该消息分发给该频道的所有订阅者,以下代码演示如何发送字符串类型的消息,将此代码片段添加到程序中:
你需要先对消息负载进行字符串序列化,才能调用 publish
方法发送消息。
// Paste the following code snippet below "Publish a message" comment
func sendMessage() {
guard !message.isEmpty else { return }
if (rtmKit != nil) {
rtmKit?.publish(channelName: channel, message: message, option: nil, completion: { response, error in
if error != nil {
self.addToMessageList(str: "publish failed error code is \(error?.errorCode.rawValue), reason is \(error?.reason)")
} else {
self.addToMessageList(str: "publish message to channel: \(self.channel) succsss")
}
})
}
message = ""
}
func addToMessageList(str: String) {
messages.append(Message(content: str))
}
调用 subscribe
方法订阅此频道以接收此频道中的消息。将以下代码添加到程序中:
// Paste the following code snippet below "Subscribe to a channel" comment
func subscribe() {
rtmKit?.subscribe(channelName: channel, option: nil, completion: { response, error in
if error != nil {
self.addToMessageList(str: "subscribe channel: \(self.channel) failed error code is \(error?.errorCode.rawValue), reason is \(error?.reason)")
} else {
self.addToMessageList(str: "susbcribe channel: \(self.channel) succsss")
}
})
}
如果你不再需要在此频道收发消息,你可以调用 unsubscribe
方法取消订阅此频道。将以下代码添加到程序中:
// Paste the following code snippet below "Unsubscribe from a channel" comment
func unsubscribe() {
rtmKit?.unsubscribe(channel, completion: { response, error in
if error != nil {
self.addToMessageList(str: "unsubscribe channel: \(self.channel) failed error code is \(error?.errorCode.rawValue), reason is \(error?.reason)")
} else {
self.addToMessageList(str: "unsusbcribe channel: \(self.channel) succsss")
}
})
}
如需了解更多收发消息的信息,查看消息。
6. 登出服务
当不再需要使用 RTM 服务时,你可以调用 logout
方法登出 RTM 系统。将以下代码添加到程序中:
// Paste the following code snippet below "Log out from the RTM server" comment
func logout() {
if rtmKit == nil {
addToMessageList(str: "RTM alreay logout!")
return
}
rtmKit?.logout()
rtmKit?.destroy()
rtmKit = nil
addToMessageList(str: "RTM logout!")
}
本操作会影响你账单中的 PCU 计费项。
7. 组合到一起
经过上述步骤,你程序中的代码应该如下所示:
import SwiftUI
import Combine
import AgoraRtmKit
struct Message: Identifiable, Equatable {
let id = UUID()
let content: String
}
class ChatViewModel: NSObject, ObservableObject, AgoraRtmClientDelegate{
// Initialize the AgoraRtmClientKit instance
var appid: String = <#YOUR APPID#>
var rtmKit: AgoraRtmClientKit? = nil
@Published var username: String = ""
@Published var message: String = ""
@Published var channel: String = ""
@Published var messages: [Message] = []
// Add the event listener
func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveLinkStateEvent event: AgoraRtmLinkStateEvent) {
addToMessageList(str: "RTM link state change current state is: \(event.currentState.rawValue) previous state is :\(event.previousState.rawValue)")
}
func rtmKit(_ rtmKit: AgoraRtmClientKit, didReceiveMessageEvent event: AgoraRtmMessageEvent) {
addToMessageList(str: "Message received.\n channel: \(event.channelName), publisher: \(event.publisher), message content: \(event.message.stringData!)")
}
// Log in the RTM server
func login() {
if rtmKit != nil {
addToMessageList(str: "RTM alreay login! Logout first!")
return
}
let config = AgoraRtmClientConfig(appId: appid, userId: username);
rtmKit = try! AgoraRtmClientKit(config, delegate: self)
rtmKit?.login(appid, completion: { response, error in
if error != nil {
self.addToMessageList(str: "login failed error code is \(error?.errorCode.rawValue), reason is \(error?.reason)")
} else {
self.addToMessageList(str: "\(self.username) login succsss")
}
})
}
// Log out from the RTM server
func logout() {
if rtmKit == nil {
addToMessageList(str: "RTM alreay logout!")
return
}
rtmKit?.logout()
rtmKit?.destroy()
rtmKit = nil
addToMessageList(str: "RTM logout!")
}
// Subscribe to a channel
func subscribe() {
rtmKit?.subscribe(channelName: channel, option: nil, completion: { response, error in
if error != nil {
self.addToMessageList(str: "subscribe channel: \(self.channel) failed error code is \(error?.errorCode.rawValue), reason is \(error?.reason)")
} else {
self.addToMessageList(str: "susbcribe channel: \(self.channel) succsss")
}
})
}
// Unsubscribe from a channel
func unsubscribe() {
rtmKit?.unsubscribe(channel, completion: { response, error in
if error != nil {
self.addToMessageList(str: "unsubscribe channel: \(self.channel) failed error code is \(error?.errorCode.rawValue), reason is \(error?.reason)")
} else {
self.addToMessageList(str: "unsusbcribe channel: \(self.channel) succsss")
}
})
}
// Publish a message
func sendMessage() {
guard !message.isEmpty else { return }
if (rtmKit != nil) {
rtmKit?.publish(channelName: channel, message: message, option: nil, completion: { response, error in
if error != nil {
self.addToMessageList(str: "publish failed error code is \(error?.errorCode.rawValue), reason is \(error?.reason)")
} else {
self.addToMessageList(str: "publish message to channel: \(self.channel) succsss")
}
})
}
message = ""
}
func addToMessageList(str: String) {
messages.append(Message(content: str))
}
}
// Set user interface
struct ContentView: View {
@StateObject private var viewModel = ChatViewModel()
var body: some View {
VStack {
TextField("input user name", text: $viewModel.username)
.padding()
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.title)
HStack {
Button(action: viewModel.login) {
Text("login")
.font(.title)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
Button(action: viewModel.logout) {
Text("logout")
.font(.title)
.padding()
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(10)
}
}
TextField("channel name", text: $viewModel.channel)
.padding()
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.title)
HStack {
Button(action: viewModel.subscribe) {
Text("subscribe")
.font(.title)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
Button(action: viewModel.unsubscribe) {
Text("unsubscribe")
.font(.title)
.padding()
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(10)
}
}
TextField("input message", text: $viewModel.message)
.padding()
.textFieldStyle(RoundedBorderTextFieldStyle())
.font(.title)
Button(action: viewModel.sendMessage) {
Text("send")
.font(.title)
.padding()
.background(Color.green)
.foregroundColor(.white)
.cornerRadius(10)
}
// display log
ScrollViewReader { scrollProxy in
List(viewModel.messages) { message in
Text(message.content)
.id(message.id)
}
.onChange(of: viewModel.messages) { _ in
if let lastMessage = viewModel.messages.last {
withAnimation {
scrollProxy.scrollTo(lastMessage.id, anchor: .bottom)
}
}
}
}
.padding()
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
现在,你可以开始运行你的程序:
- 保存项目。
- 复制当前项目,使用相同的
appId
和不同的userId
。 - 运行上面的两个项目。成功运行后,你可以在两个设备中看到 App 界面。
- 将一个设备作为接收端,进行如下操作:
- 输入用户名,点击 login。
- 输入频道名,点击 subscribe。
- 将另一个设备作为发送端,进行如下操作:
- 输入不同的用户名,点击 subscribe。
- 输入相同的频道名。
- 输入消息,点击 send。
- 将上面的发送端和设备端互换,重复步骤 4 和 5。
如果两个设备均可收发消息,那么你已经成功集成并正确使用了 RTM 服务。
贯穿始终
相比于介绍如何写出代码,声网更愿意帮助你掌握上述程序编写的过程和逻辑。上述程序依次完成了以下操作,让你可以正确地收发消息:
- 设置并初始化 RTM 对象。
- 添加
didReceiveMessageEvent
事件监听函数。 - 调用
login
登录了 RTM 服务。 - 调用
subscribe
订阅了一个 Message Channel。 - 调用
publish
发送消息。 - 调用
unsubscribe
取消订阅一个 Message Channel。 - 调用
logout
登出 RTM 系统。
下一步
现在,你已经学会了如何使用 RTM Swift SDK 来实现 Message Channel 的收发消息功能。下一步,你可以通过 SDK 的 API 参考了解更多功能的使用方法。