本文介绍如何使用声网 SDK 快速实现云信令。
登录 RTM 系统包括以下流程:
发送和接收点对点消息包括以下流程:
发送和接收频道消息包括以下流程:
参考以下步骤创建一个声网项目:
声网会给每个项目自动分配一个 App ID 作为项目唯一标识。
在声网控制台的项目管理页面,找到你的项目,点击 App ID 右侧的 图标,即可获取项目的 App ID。
参考以下步骤获取 App 证书:
在声网控制台的项目管理页面,找到你的项目,点击配置。
点击主要证书下面的复制图标,即可获取项目的 App 证书。
为提高项目的安全性,声网推荐使用 Token 对即将登录 RTM 系统的用户进行鉴权。
为了方便测试,声网服务器提供部署签发 RTM Token 的功能。参考以下步骤获取 RTM Token:
login
时,请确保填入的用户 ID 与生成 RTM Token 时填入的用户 ID 一致。前往 SDK 下载页面,在云信令 (原 RTM) SDK 中下载最新版本的声网 RTM SDK,然后解压。
将 SDK 包内 libs
下的 Rtm-Scripts
文件夹拷贝到项目路径的 Assets
文件夹下。
将 SDK 包内 libs/Plugins
路径下的如下文件,拷贝到项目的对应路径下:
开发平台 | 文件或文件夹 | 项目路径 |
---|---|---|
Android | Plugins/Android |
/Assets/Plugins/Android/ |
iOS | Plugins/iOS |
/Assets/Plugins/iOS |
macOS | Plugins/macOS |
/Assets/Plugins/macOS |
Windows | Plugins/x86 |
/Assets/Plugins/x86 |
Windows | Plugins/x86_64 |
/Assets/Plugins/x86_64 |
在 Unity 中创建以下用户界面元素:
Canvas
在 scene 中创建一个空的 GameObject,命名为 MessageManager
。在 GameObject 中添加两个 script:
MessageManager.cs
: 发送和接收消息的基本逻辑。MessageDisplay.cs
: 在用户界面上显示消息和状态变更。MessageManager.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using agora_rtm;
namespace io.agora.rtm.quickstart
{
public class MessageManager : MonoBehaviour
{
// 序列化字段,可用于在 Unity Editor 中填入 App ID 和 Token
[Header("Agora Properties")]
[SerializeField]
private string appId = "";
[SerializeField]
private string token = "";
// 序列化字段,可用于在 Unity Editor 中连接 Unity 对象和脚本变量
[Header("Application Properties")]
[SerializeField] InputField userNameInput, channelNameInput;
[SerializeField] InputField channelMsgInputBox;
[SerializeField] InputField peerUserBox;
[SerializeField] InputField peerMessageBox;
[SerializeField] MessageDisplay messageDisplay;
private RtmClient rtmClient = null;
private RtmChannel channel;
private RtmClientEventHandler clientEventHandler;
private RtmChannelEventHandler channelEventHandler;
private RtmCallEventHandler callEventHandler;
string _userName = "";
string UserName {
get { return _userName; }
set {
_userName = value;
PlayerPrefs.SetString("RTM_USER", _userName);
PlayerPrefs.Save();
}
}
string _channelName = "";
string ChannelName
{
get { return _channelName; }
set {
_channelName = value;
PlayerPrefs.SetString("RTM_CHANNEL", _channelName);
PlayerPrefs.Save();
}
}
agora_rtm.SendMessageOptions _MessageOptions = new agora_rtm.SendMessageOptions() {
enableOfflineMessaging = true,
enableHistoricalMessaging = true
};
private void Awake()
{
userNameInput.text = PlayerPrefs.GetString("RTM_USER", "");
channelNameInput.text = PlayerPrefs.GetString("RTM_CHANNEL", "");
}
// 初始化
void Start()
{
clientEventHandler = new RtmClientEventHandler();
channelEventHandler = new RtmChannelEventHandler();
callEventHandler = new RtmCallEventHandler();
rtmClient = new RtmClient(appId, clientEventHandler);
#if UNITY_EDITOR
rtmClient.SetLogFile("./rtm_log.txt");
#endif
clientEventHandler.OnQueryPeersOnlineStatusResult = OnQueryPeersOnlineStatusResultHandler;
clientEventHandler.OnLoginSuccess = OnClientLoginSuccessHandler;
clientEventHandler.OnLoginFailure = OnClientLoginFailureHandler;
clientEventHandler.OnMessageReceivedFromPeer = OnMessageReceivedFromPeerHandler;
channelEventHandler.OnJoinSuccess = OnJoinSuccessHandler;
channelEventHandler.OnJoinFailure = OnJoinFailureHandler;
channelEventHandler.OnLeave = OnLeaveHandler;
channelEventHandler.OnMessageReceived = OnChannelMessageReceivedHandler;
}
void OnApplicationQuit()
{
if (channel != null)
{
channel.Dispose();
channel = null;
}
if (rtmClient != null)
{
rtmClient.Dispose();
rtmClient = null;
}
}
// 登录系统
public void Login()
{
UserName = userNameInput.text;
if (string.IsNullOrEmpty(UserName) || string.IsNullOrEmpty(appId))
{
Debug.LogError("We need a username and appId to login");
return;
}
rtmClient.Login(token, UserName);
}
// 登出系统
public void Logout()
{
messageDisplay.AddTextToDisplay(UserName + " logged out of the rtm", Message.MessageType.Info);
rtmClient.Logout();
}
// 加入频道
public void JoinChannel()
{
ChannelName = channelNameInput.GetComponent<InputField>().text;
channel = rtmClient.CreateChannel(ChannelName, channelEventHandler);
ShowCurrentChannelName();
channel.Join();
}
// 离开频道
public void LeaveChannel()
{
messageDisplay.AddTextToDisplay(UserName + " left the chat", Message.MessageType.Info);
channel.Leave();
}
// 发送频道消息
public void SendMessageToChannel()
{
string msg = channelMsgInputBox.text;
string peer = "[channel:" + ChannelName + "]";
string displayMsg = string.Format("{0}->{1}: {2}", UserName, peer, msg);
messageDisplay.AddTextToDisplay(displayMsg, Message.MessageType.PlayerMessage);
channel.SendMessage(rtmClient.CreateMessage(msg));
}
// 发送点对点消息
public void SendPeerMessage()
{
string msg = peerMessageBox.text;
string peer = peerUserBox.text;
string displayMsg = string.Format("{0}->{1}: {2}", UserName, peer, msg);
messageDisplay.AddTextToDisplay(displayMsg, Message.MessageType.PlayerMessage);
rtmClient.SendMessageToPeer(
peerId: peer,
message: rtmClient.CreateMessage(msg),
options: _MessageOptions
);
peerMessageBox.text = "";
}
void ShowCurrentChannelName()
{
ChannelName = channelNameInput.GetComponent<InputField>().text;
Debug.Log("Channel name is " + ChannelName);
}
void OnQueryPeersOnlineStatusResultHandler(int id, long requestId, PeerOnlineStatus[] peersStatus, int peerCount, QUERY_PEERS_ONLINE_STATUS_ERR errorCode)
{
if (peersStatus.Length > 0)
{
Debug.Log("OnQueryPeersOnlineStatusResultHandler requestId = " + requestId +
" peersStatus: peerId=" + peersStatus[0].peerId +
" online=" + peersStatus[0].isOnline +
" onlinestate=" + peersStatus[0].onlineState);
messageDisplay.AddTextToDisplay("User " + peersStatus[0].peerId + " online status = " + peersStatus[0].onlineState, Message.MessageType.Info);
}
}
// 加入频道成功回调
void OnJoinSuccessHandler(int id)
{
string msg = "channel:" + ChannelName + " OnJoinSuccess id = " + id;
Debug.Log(msg);
messageDisplay.AddTextToDisplay(msg, Message.MessageType.Info);
}
// 加入频道失败回调
void OnJoinFailureHandler(int id, JOIN_CHANNEL_ERR errorCode)
{
string msg = "channel OnJoinFailure id = " + id + " errorCode = " + errorCode;
Debug.Log(msg);
messageDisplay.AddTextToDisplay(msg, Message.MessageType.Error);
}
// 登录成功回调
void OnClientLoginSuccessHandler(int id)
{
string msg = "client login successful! id = " + id;
Debug.Log(msg);
messageDisplay.AddTextToDisplay(msg, Message.MessageType.Info);
}
// 登录失败回调
void OnClientLoginFailureHandler(int id, LOGIN_ERR_CODE errorCode)
{
string msg = "client login unsuccessful! id = " + id + " errorCode = " + errorCode;
Debug.Log(msg);
messageDisplay.AddTextToDisplay(msg, Message.MessageType.Error);
}
// 离开频道回调
void OnLeaveHandler(int id, LEAVE_CHANNEL_ERR errorCode)
{
string msg = "client onleave id = " + id + " errorCode = " + errorCode;
Debug.Log(msg);
messageDisplay.AddTextToDisplay(msg, Message.MessageType.Info);
}
// 收到频道消息回调
void OnChannelMessageReceivedHandler(int id, string userId, TextMessage message)
{
Debug.Log("client OnChannelMessageReceived id = " + id + ", from user:" + userId + " text:" + message.GetText());
messageDisplay.AddTextToDisplay(userId + ": " + message.GetText(), Message.MessageType.ChannelMessage);
}
// 收到点对点消息回调
void OnMessageReceivedFromPeerHandler(int id, string peerId, TextMessage message)
{
Debug.Log("client OnMessageReceivedFromPeer id = " + id + ", from user:" + peerId + " text:" + message.GetText());
messageDisplay.AddTextToDisplay(peerId + ": " + message.GetText(), Message.MessageType.PeerMessage);
}
// 加入频道回调
void OnMemberJoinedHandler(int id, RtmChannelMember member)
{
string msg = "channel OnMemberJoinedHandler member ID=" + member.GetUserId() + " channelId = " + member.GetChannelId();
Debug.Log(msg);
messageDisplay.AddTextToDisplay(msg, Message.MessageType.Info);
}
// 离开频道回调
void OnMemberLeftHandler(int id, RtmChannelMember member)
{
string msg = "channel OnMemberLeftHandler member ID=" + member.GetUserId() + " channelId = " + member.GetChannelId();
Debug.Log(msg);
messageDisplay.AddTextToDisplay(msg, Message.MessageType.Info);
}
// 发送消息结果回调
void OnSendMessageResultHandler(int id, long messageId, PEER_MESSAGE_ERR_CODE errorCode)
{
string msg = string.Format("Sent message with id:{0} MessageId:{1} errorCode:{2}", id, messageId, errorCode);
Debug.Log(msg);
messageDisplay.AddTextToDisplay(msg, errorCode == PEER_MESSAGE_ERR_CODE.PEER_MESSAGE_ERR_OK ? Message.MessageType.Info : Message.MessageType.Error);
}
// 链接状态变更回调
void OnConnectionStateChangedHandler(int id, CONNECTION_STATE state, CONNECTION_CHANGE_REASON reason)
{
string msg = string.Format("connection state changed id:{0} state:{1} reason:{2}", id, state, reason);
Debug.Log(msg);
messageDisplay.AddTextToDisplay(msg, Message.MessageType.Info);
}
}
}
MessageDisplay.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace io.agora.rtm.quickstart
{
public class MessageDisplay : MonoBehaviour
{
#pragma warning disable 0649
[SerializeField] int maxMessages = 25;
[SerializeField] GameObject chatPanel, textPrefab;
[SerializeField] MessageColorStruct MessageColors;
[SerializeField] List<Message> messageList = new List<Message>();
#pragma warning restore 0649
private void Awake()
{
}
// 将 Text 转化为 prefab 并添加到 ScrollView 的 Content 对象,从而实现文字的逐行显示
public void AddTextToDisplay(string text, Message.MessageType messageType)
{
if (messageList.Count >= maxMessages)
{
Destroy(messageList[0].textObj.gameObject);
messageList.Remove(messageList[0]);
}
Message newMessage = new Message();
newMessage.text = text;
GameObject newText = Instantiate(textPrefab, chatPanel.transform);
newMessage.textObj = newText.GetComponent<Text>();
newMessage.textObj.text = newMessage.text;
newMessage.textObj.color = MessageTypeColor(messageType);
messageList.Add(newMessage);
}
public void Clear()
{
foreach (Message msg in messageList) {
Destroy(msg.textObj.gameObject);
}
messageList.Clear();
}
Color MessageTypeColor(Message.MessageType messageType)
{
Color color = MessageColors.infoColor;
switch (messageType)
{
case Message.MessageType.PlayerMessage:
color = MessageColors.playerColor;
break;
case Message.MessageType.ChannelMessage:
color = MessageColors.channelColor;
break;
case Message.MessageType.PeerMessage:
color = MessageColors.peerColor;
break;
case Message.MessageType.Error:
color = MessageColors.errorColor;
break;
}
return color;
}
}
[System.Serializable]
public class Message
{
public string text;
public Text textObj;
public MessageType messageType;
public enum MessageType
{
Info,
Error,
PlayerMessage,
ChannelMessage,
PeerMessage
}
}
[System.Serializable]
public struct MessageColorStruct
{
public Color infoColor, errorColor, playerColor, peerColor, channelColor;
}
}
MessageManager.Login
MessageManager.SendPeerMessage
MessageManager.Logout
MessageManager.JoinChannel
MessageManager.SendMessageToChannel
MessageManager.LeaveChannel
Agora Properties
字段中填入 App ID 和 Token。