古語有云 “烽火連三月,家書抵萬金”,在通信技術匱乏的古代,信息傳遞艱難險阻重重,一封家書寄托著人們對消息及時、準確的深切期盼。而在當今蓬勃發展的數字游戲世界中, 游戲內實時通信 恰似維系玩家社交生態的 “烽火臺” 與 “家書”,已然成為提升玩家沉浸感與社交體驗的核心關鍵要素。
無論是組隊協作時精準下達的戰術指令、跨服活動中實時發布的重要公告,還是好友之間私密親切的對話交流,游戲開發者都迫切需要一套高效、靈活且穩定可靠的游戲內消息推送系統,以此保障信息能夠快速、準確地傳遞到每一位玩家手中。Unity Online Services(UOS)推出的 Push 應運而生,它憑借輕量化的集成方式和強大完備的功能模塊,為游戲內的實時聊天、事件通知及多樣化的社交互動,提供了覆蓋全流程、全方位的解決方案。
本教程將基于 UOS Push 服務搭建的一個在線聊天室的示例程序,來講解 Push 是如何實現游戲內實時消息推送的。大家可以進入下方的 UOS 官網鏈接,進行在線體驗哦!
https://uos.unity.cn/playground/push
本教程中涉及 UOS 服務包括:
服務器推送服務 Push:可實現游戲內實時消息推送
服務器推送服務 Push
UOS Push 是 Unity 資深團隊打造的專業游戲內實時信息推送服務,它是一款支持數十萬人甚至上百萬玩家同時在線的分布式游戲內實時消息推送系統,具備強大的技術實力與卓越的性能表現。
“實時” 是 UOS Push 的核心優勢之一。游戲系統能夠借助 Push 服務即時地向玩家發送各類相關的消息和通知,無論是游戲內的實時聊天系統(涵蓋世界聊天、團隊聊天、群組聊天、一對一的私聊),還是系統發布的公告通知,都能在瞬間傳達給目標玩家,為玩家帶來近乎零延遲的信息交互體驗。
面對高并發的場景,UOS Push 同樣表現出色。在游戲活動、賽事等玩家活躍度極高的時刻,大量玩家同時發送和接收消息,UOS Push 能夠憑借其分布式的架構和算法,高效處理海量的消息請求,確保消息的準確、及時推送,不會出現消息丟失或延遲過長的情況,為玩家打造流暢、穩定的信息交互環境。
UOS Push 的應用場景豐富多元,在游戲社交與運營中發揮關鍵作用:
游戲內聊天:在多人在線游戲中,玩家需要實時溝通策略、分享游戲體驗。UOS Push 支持即時文字傳輸,無論是組隊刷副本時快速交流戰術細節,還是在世界頻道與其他玩家暢聊游戲趣事,都能瞬間送達,打破玩家間的溝通壁壘,讓社交互動更流暢自然,顯著提升玩家的參與感和游戲粘性。
游戲內實時公告:游戲官方推出限時活動、版本更新、服務器維護等重要信息時,UOS Push 可將公告精準、快速地推送給所有玩家。即使玩家處于游戲內不同界面,對于未在線的玩家,UOS Push 會將消息進行緩存,一旦玩家上線,緩存的消息就會即刻送達,避免錯過關鍵內容,確保玩家及時了解游戲動態,提升活動參與度和游戲運營效率。
好友對戰邀請:當玩家向好友發起對戰邀請時,UOS Push 能立即將邀請信息發送至對方設備。在收到推送提醒后,一鍵點擊接受邀請,可無縫切入對戰環節,簡化操作流程,讓好友間的即時對戰更加便捷,增強游戲的社交競技樂趣 。
教程視頻
教程學習大綱
創建項目,開啟 Push 服務并安裝 SDK
在項目中接入 Push SDK
訂閱頻道(公共頻道/非公共頻道)
發送頻道消息
SDK 狀態管理與斷開連接后的處理
教程示例程序
教程內學習用到的項目素材資源,是通過在 UOS Launcher 窗口中直接在線安裝的。大家也可以通過下面提供的鏈接查看 Push SDK 的示例程序。
Push SDK代碼倉庫的地址:
https://unitychina.coding.net/public/uos/PushSDK/git/files/master/Sample~
教程操作步驟
接下來讓我們來看看 UOS Push 在項目中的具體用法吧!
1. 創建項目,開啟 Push 服務并安裝 SDK
1.1 創建項目工程
打開 Unity Hub,選擇創建「新項目」,教程這里使用的 Unity 編輯器版本是 2022.3.55f1c1 版本,大家可以自行選擇電腦上已安裝的版本。項目模板可以選擇「3D(Built-in)」,自定義項目名稱和位置。可以勾選選項「啟用游戲云服務」,勾選后會自動為你的項目工程安裝 UOS Launcher 的。
最后點擊「創建項目」,等待項目的創建和加載。
1.2 綁定 UOS App
溫馨提示:當前項目中已安裝好 UOS Launcher,不需要再次安裝了。大家可以參考之前的的公眾號文章教程,來為你當前的項目綁定你創建好的 UOS App 。
點擊 Launcher 面板的「LinkApp」按鈕,在彈出窗口中選擇「By Unity project」,在「Select organization」這里選擇一個自己的項目組織,然后在「Select project 」選項這里,我們選擇「Create a new project 」,自行設置修改項目名字「Project name」,最后點擊「LinkApp」按鈕即可。
教程中,我們就先選擇綁定創建好的 UOSPushDemo 應用了。
1.3 開啟 Push 服務并安裝 Push SDK
在編輯器內 Unity Online Services 窗口的下拉服務列表中,找到「Push」,點擊「Enable」開啟服務,并安裝 Push SDK。
1.4 導入項目示例資源包,打開 Sample 場景
在 UOS Launcher 中點擊「import sample」按鈕,即可導入項目示例工程資源包。
該項目是基于 UOS Push 服務搭建的一個在線聊天室的示例程序, 展示了 SDK 基本接口的使用方式。
導入資源包后,在如圖所示的路徑下,找到 Scene.unity 示例場景并打開。
在彈出的窗口中,點擊「Import TMP Essentials」來導入 TextMeshPro 的字體資源。
游戲的 Game 窗口打開界面如下:
2. 在項目中接入 Push SDK
Push 客戶端 SDK 接入指南參考鏈接:
https://uos.unity.cn/doc/push/client-sdk
2.1 初始化 Push SDK 和 SDK 鑒權
在線聊天室的示例程序的核心控制代碼腳本是 PushSample.cs,已經掛載在了場景中的空對象 PushSample 上。
在腳本的 Awake 方法中,調用PushSDK.InitializeAsync 方法來初始化 Push SDK,當前傳入了三個參數:
OnConnected:連接成功或失敗后的回調方法;
OnMessage:收到消息的回調方法;
OnDisconnected:心跳檢測失敗或是其他異常問題導致客戶端連接斷開時,會
響應該方法,響應該方法后,等于退出連接,此前訂閱的頻道信息將被清空。
到后面我們再詳細講解這三個回調方法。大家根據自己的需求,初始化時還可以自行選擇是否傳入訂閱頻道的回調方法、用戶被異地登錄時的回調方法、離線玩家消息的回調方法,以及所使用的傳輸協議類型。
TransportProtocol:傳輸協議, 可選項為 Websocket 和 KCP。
Websocket 能更實時檢測連接的開始和關閉,能提供更加穩定的連接;
KCP 能提供更低延遲的傳輸效率。微信小游戲請使用 KCP 協議,如需在小游
戲里使用 Websocket 協議, 請聯系我們!
在沒有使用 Passport Login SDK 的情況下,調用ExternalLogin方法,使用外部賬號登錄的方式來進行 SDK 鑒權以獲取 AccessToken。
public class PushSample : MonoBehaviour
{
private readonly string _userID = Guid.NewGuid().ToString();
private string _userName = "uos_test";
private async void Awake()
{
//......
// 初始化PushSDK
await PushSDK.InitializeAsync(OnConnected, OnMessage, OnDisconnected);
// 登陸
await AuthTokenManager.ExternalLogin(_userID, _userID, _userName);
}
//......
}
2.2 游戲登錄界面初始化用戶名
游戲 Demo 運行后,在彈出的 UI 窗口中,會先隨機一個用戶名,然后點擊「進入」按鈕即可加入聊天室。
登錄界面上的 UI 控件,對應場景中的游戲對象 SigninUI,它身上已經綁定了 SigninUI.cs 腳本。
在 SigninUI.cs 腳本的 Start 方法中,會調用 SetRandomName 方法來隨機得到一個用戶名。
public class SigninUI : MonoBehaviour
{
[SerializeField] private TMP_InputField usernameInputField;
[SerializeField] private Button signinButton;
private List
usernameList = new List
() { "MightyWarrior", "SilentShadow", //...... }; private void Start() { _instance = this; SetRandomName(); Show(true); } private void SetRandomName() { var index = Random.Range(0, usernameList.Count); usernameInputField.text = usernameList[index]; } //...... }
2.3 連接至 Push 服務器,進入聊天室
場景中的「進入」按鈕對象上,已經注冊綁定了 PushSample.cs 腳本中的 JoinRoom 方法。
當點擊 “進入” 按鈕時,會執行 JoinRoom 方法。通過調用 PushSDK 提供的 ConnectAsync 方法,來連接到 Push Server 端,傳入兩個參數:
玩家 ID:其他的玩家將通過此 ID 向你發送消息;
玩家用戶名:當發送消息時,我們將使用之前輸入框里面的用戶名,作為聊天時對方可顯示的你的玩家名。
public async void JoinRoom()
{
SigninUI.SetLoading(true);
_userName = SigninUI.GetUsername();
try
{
// 連接到PushServer
await PushSDK.Instance.ConnectAsync(_userID,_userName);
}
catch (PushSDKClientException e)
{
Debug.LogErrorFormat("Failed to init pushSdk and connect server. clientEx {0}", e);
}
catch (PushSDKServerException e)
{
Debug.LogErrorFormat("Failed to init pushSdk and connect server. serverEx {0}", e);
}
catch (AuthException e)
{
Debug.LogErrorFormat("Failed to init pushSdk and connect server. authEx {0}", e);
}
LoadingUI.Show(true);
}
3.1 頻道的概念
3. 訂閱頻道(公共頻道/非公共頻道)
頻道是 UOS Push 系統中用于推送和收取信息最小單位,頻道可分為公共頻道和非公共頻道:
公共頻道:任何人都可以加入、查看和參與的頻道,可用于世界服聊天和對所有玩家發布系統通知。公共頻道需預先配置,無法通過客戶端 SDK 創建公共頻道。
非公共頻道:無需預先配置,可通過客戶端 SDK 創建和訂閱。這種頻道通常可用于對特定的團隊或群體開放,例如在線游戲中的團隊/小隊聊天頻道、公會聊天頻道等。
對于頻道消息,在線且訂閱頻道的玩家應該實時收到頻道消息,同時支持頻道消息緩存。
3.2 創建公共頻道
進入 UOS 網頁端的「Push -> 頻道管理」頁面,點擊「創建公共頻道」按鈕。
在彈出的窗口中,輸入:頻道名稱(名稱不能重復),并點擊「創建」按鈕。
然后就可以看到創建好的公共頻道 TestChannel 了。如果用戶訂閱了當前頻道,還可以看到當前頻道的在線人數。
3.3 封裝訂閱頻道的方法
當連接 Push Server 成功后,可以訂閱需要訂閱的頻道。在這里,我們封裝一個 SubscribeChannel 方法來實現,方法內需要傳入要訂閱的頻道的名字(channelName),以及該頻道是否為公共頻道(isPublic)。
在方法內會做出以下的處理:
將調用 Push SDK 提供的 SubscribeChannels 方法來實現訂閱頻道;
同時將訂閱過的頻道加入集合列表(AllChannels)中進行保存;
并將該頻道添加到 UI 組件上進行顯示出來;
當訂閱需要訂閱的頻道時,調用 ChatRoomUI.cs 腳本中的 ShowMessage 方法,在聊天室界面上顯示 “連接聊天室成功” 的系統消息。
// 所有頻道的集合
private static readonly List
AllChannels = new(); //訂閱頻道的方法 private static void SubscribeChannel(string channelName, bool isPublic) { if (AllChannels.Contains(channelName)) { return; } // 訂閱頻道 PushSDK.Instance.SubscribeChannels(new List
(){channelName}, isPublic); // 添加到 UI 組件用于顯示 AllChannels.Add(channelName); ChatRoomUI.Instance.AddChannel(channelName, isPublic); ChatRoomUI.ShowMessage(new List
(){channelName},"連接聊天室成功", (uint)_userID.GetHashCode(), UIMessageType.System); }
3.4 連接 Push Server 后的回調方法(OnConnected )
當客戶端連接 Push 服務器后,會自動響應初始化 Push SDK 時傳入的 OnConnected 回調方法,來判斷連接的結果(ConnectResult)是成功還是失敗。
3.4.1 連接成功后訂閱頻道
連接成功后,會訂閱需要訂閱的頻道。
溫馨提醒:頻道名稱不可以重復,需要全局唯一,公共頻道和非公共頻道的名稱也不可以重復。
訂閱非公共頻道:
先定義變量 ChannelGuild001 來模擬公會頻道,變量 ChannelGroup001 來模擬群組頻道。
然后添加判斷,如果連接結果(ConnectResult )中的變量(Success)為 true,說明連接成功了。則在 SubscribeChannels 方法中傳入 false 來訂閱這些非公共頻道(ChannelGuild001 、ChannelGroup001 )。
private const string ChannelGuild001 = "Guild001";
private const string ChannelGroup001 = "Group001";
///
/// 連接push server 完成的回調方法
///
/// 連接結果
private async void OnConnected(ConnectResult connectResult)
{
if (connectResult.Success)
{
// 連接成功后,訂閱需要訂閱的頻道
// 訂閱一些團隊頻道,比如加入的公會,群組等。
SubscribeChannel(ChannelGroup001, false);
SubscribeChannel(ChannelGuild001, false);
//......
}
//......
}
訂閱公共頻道:
訂閱公共頻道時,需要先調用 Push SDK 提供的 ListPublicChannelInfoAsync 方法,返回值將記錄獲取到的當前所有可用的公共頻道信息。
然后我們將遍歷 UOS 網頁端創建的每一個公共頻道,然后在SubscribeChannels 方法中傳入 true 來訂閱這些公共頻道。
private async void OnConnected(ConnectResult connectResult)
{
if (connectResult.Success)
{
// 訂閱一些團隊頻道,比如加入的公會,群組等
// ......
// 查看并訂閱當前所有的公共頻道
try
{
var list = await PushSDK.Instance.ListPublicChannelInfoAsync();
foreach (var item in list)
{
SubscribeChannel(item.Name, true);
}
}
catch (PushSDKClientException e)
{
Debug.LogErrorFormat("Failed to list channels. clientEx {0}", e);
}
catch (PushSDKServerException e)
{
Debug.LogErrorFormat("Failed to list channels. serverEx {0}", e);
}
SigninUI.Show(false);
LoadingUI.Show(false);
ChatRoomUI.Instance.ActiveFirstChannel();
}
并隱藏登錄界面(SigninUI)和加載界面(LoadingUI),同時 UI 界面上會激活顯示頻道列表中的第一個頻道面板。
3.4.2 連接失敗時的處理
當連接 Push Server 失敗時,會在聊天室界面上顯示 “連接聊天室失敗” 的系統消息。同時也會顯示出登錄界面(SigninUI),允許用戶重新嘗試登錄。
private async void OnConnected(ConnectResult connectResult)
{
if (connectResult.Success)
{
//......
}
else
{
ChatRoomUI.ShowMessage(AllChannels.ToList(), "連接聊天室失敗", (uint)_userID.GetHashCode(), UIMessageType.System);
SigninUI.Show(true);
LoadingUI.Show(false);
}
}
3.5 運行項目查看日志信息
此時運行項目后, Game 窗口的界面為:
在 Console 控制臺窗口,輸出的也會有相關的頻道訂閱日志:
4. 發送頻道消息
頻道消息可用于團隊、世界服聊天。
4.1 場景中發送消息的 UI 按鈕
在聊天室界面上,選擇了頻道后,可以點擊發送消息。「發送」的按鈕上,已經注冊綁定了當前頻道對象 (ChannelPanel(Clone))上的腳本 ChannelPanel.cs 中的方法 SendMessage。
在 SendMessage 方法中,會判斷如果輸入消息框中內容不為空,會調用 PushSample.cs 腳本中的 SendMessage 方法來發送消息,同時會清空消息輸入框的文字。
public class ChannelPanel : MonoBehaviour
{
//......
[SerializeField] private TMP_InputField inputMessage;
public void SendMessage()
{
var msg = inputMessage.text;
if (!string.IsNullOrEmpty(msg))
{
PushSample.SendMessage(_channelIndex, inputMessage.text);
inputMessage.text = "";
}
}
}
4.2 發送頻道消息
在 PushSample.cs 腳本的 SendMessage 方法中,會調用 Push SDK 提供的 SendChannelMessage 方法來向指定的頻道發送消息。
傳入兩個參數:頻道名稱、發送的消息內容。頻道名稱可通過頻道索引從 AllChannels 集合中獲取到。
public class PushSample : MonoBehaviour
{
//......
public static void SendMessage(int index, string message)
{
PushSDK.Instance.SendChannelMessage(AllChannels[index], System.Text.Encoding.UTF8.GetBytes(message));
}
}
4.3 收到消息的回調方法(OnMessage)
收到消息后,會自動回調在初始化 Push SDK 時傳入的 OnMessage 方法來處理接收到的推送消息,并將其正確解析后顯示到聊天界面上。
方法的參數 PushMessage 會記錄:消息發送方 Id、消息發送方名字、收到頻道消息時的頻道名、收到消息所屬的消息類型「公共頻道消息/其他頻道消息/玩家消息」、消息內容、消息發送時間戳「UTC 時間」。
parsedMessage表示解析后的消息內容;
然后判斷下如果消息發送者的 Id 和當前用戶的 Id 一樣,則說明該消息是當前用戶自己發送的;否則是其它用戶發送的消息。同時根據消息發送方的不同,會顯示不同的 UI 界面的。
///
/// 收到消息的回調方法
///
/// 收到的消息
private void OnMessage(PushMessage message)
{
Debug.Log("收到消息的回調方法,對應頻道是:" + message.ChannelName);
var parsedMessage = System.Text.Encoding.UTF8.GetString(message.Data);
var ourSide = message.SenderId == _userID;
ChatRoomUI.ShowMessage(new List
(){message.ChannelName},parsedMessage, (uint)_userID.GetHashCode(), ourSide ? UIMessageType.OurSide: UIMessageType.OtherSide, message.SenderName); }
4.4 測試收發消息
我們可以選擇一個在編輯器中 Play 模式下測試,另一個提前 Build 成 exe 文件運行游戲。
構建 Build 文件
將當前場景添加到File → BuildSettings列表中,即可點擊「Build」按鈕,生成一個可執行文件。
同時運行兩個客戶端 exe 文件,游戲界面如下:
4.5 緩存消息處理
當新上線的玩家訂閱同一個頻道后,會看到該頻道內之前的消息,Game 窗口的 UI 界面如下所示:
對于試用用戶來說,頻道消息緩存限制為 5 條,也就是說當新用戶加入同一個頻道后,會顯示最新的未讀消息,最多為 5 條,我們在 UI 界面上可以看到數量和消息內容。
同時,查看 Console 控制臺窗口的日志消息:可以看到新用戶在訂閱了對應頻道(Group001/Guild001/TestChannel)后,會自動觸發 OnMessage 回調方法,方法調用的次數和未讀消息的數量是一致的。
回調方法 OnMessage 之前已經講解過,這里不再詳細闡述。
///
/// 收到消息的回調方法
///
/// 收到的消息
private void OnMessage(PushMessage message)
{
Debug.Log("收到消息的回調方法,對應頻道是:" + message.ChannelName );
var parsedMessage = System.Text.Encoding.UTF8.GetString(message.Data);
var ourSide = message.SenderId == _userID;
ChatRoomUI.ShowMessage(new List
(){message.ChannelName},parsedMessage, (uint)_userID.GetHashCode(), ourSide ? UIMessageType.OurSide: UIMessageType.OtherSide, message.SenderName); }
大家可以自行查看下 ChatRoomUI.cs 腳本中的 ShowMessage 方法,在方法中會遍歷所有訂閱的頻道,然后在對應頻道的面板中顯示消息。
如果是來自其他玩家的消息(UIMessageType.OtherSide),還會調用 ChannelTab.cs 腳本中的 AddUnreadMessageCount 方法,在標簽頁上增加未讀消息計數,同時將消息內容同步顯示在 UI 界面上。
public class ChatRoomUI: MonoBehaviour
{
//......
public static void ShowMessage(List
channels, string text, uint playerID, UIMessageType type, string playerName = "") { for (var i = 0; i < channels.Count; i += 1) { var channel = channels[i]; var index = ChannelNameToIndex[channel]; var targetPanel = _instance._channelPanels[index]; targetPanel.Add(text, playerID, type, playerName); if (type == UIMessageType.OtherSide) { var targetTab = _instance._channelTabs[index]; targetTab.AddUnreadMessageCount(); } } }
5.1 SDK 狀態管理
5. SDK 狀態管理與斷開連接后的處理
Push SDK Instance 存在以下 5 種狀態:
init (初始狀態):Push SDK 初始化成功后就是該狀態。
connecting (正在連接中):調用 ConnectAsync 方法開始連接,或斷線后自動重連階段,處于該狀態。
connected (連接成功):成功連上 Push Server 處于該狀態。
connectFailure (連接失敗):因網絡故障等原因無法連接到 Push Server 時會處于該狀態。
disconnected (已斷開連接):客戶端主動調用 Disconnect 方法或是斷線重連失敗后會處于該狀態。
public class PushSDK : MonoBehaviour, IPushSDK
{
public const string StatusInit = "init"; // 初始狀態
public const string StatusConnected = "connected"; // 連接成功
public const string StatusConnectFailure = "connectFailure"; // 連接失敗
public const string StatusDisconnected = "disconnected"; // 已斷開連接
public const string StatusConnecting = "connecting"; // 正在連接中
//......
}
Push SDK Instance 狀態轉換關系如下圖:
5.2 斷開連接
當和 Push Server 斷開連接時,會自動響應初始化 Push SDK 時傳入的 OnDisconnected 方法。
正常斷開連接時(IsNormalClosed 為 true):會重新顯示登錄界面,如果程序還在運行,就在所有訂閱頻道上顯示一條系統消息“已退出聊天室”。
異常斷開連接時:會調用 ConnectAsync 方法自動嘗試重新連接。
///
/// 斷開連接的回調方法
///
/// 是否正常斷開連接
private void OnDisconnected(DisconnectResult disconnectResult)
{
if (disconnectResult.IsNormalClosed)
{
// 正常斷開連接
SigninUI.Show(true);
if (!Application.isPlaying) return;
ChatRoomUI.ShowMessage(AllChannels.ToList(),"已退出聊天室", (uint)_userID.GetHashCode(), UIMessageType.System);
}
else
{
// 異常斷開連接,需要重連
PushSDK.Instance.ConnectAsync(_userID, _userName);
}
}
當用戶退出應用程序時:自動回調 OnApplicationQuit 方法,如果當前處于已連接狀態(StatusConnected),就調用 Disconnect 方法主動斷開連接,釋放網絡連接資源。
private void OnApplicationQuit()
{
// 程序退出時斷開連接
if (PushSDK.Instance.ConnectionStatus() == PushSDK.StatusConnected)
{
PushSDK.Instance.Disconnect();
}
}
寄語
通過本次教程搭建的在線聊天室示例,相信大家對 UOS Push 的實時消息推送能力已有直觀了解。期待開發者們利用 UOS Push,打造出更多充滿社交活力與互動樂趣的精彩游戲!
如果想了解客戶端接入 Push SDK 時更多 API 的使用方法,歡迎訪問 UOS 網頁端進行查看:
https://uos.unity.cn/doc/push/client-sdk
本期教程我們先講解到這里,大家趕快下載 Demo 項目試試吧!我們下一期再見哦!
Unity Online Services (UOS) 是一個專為游戲開發者設計的一站式游戲云服務平臺,提供覆蓋游戲全生命周期的開發、運營和推廣支持。
了解更多 UOS 相關信息:
官網:https://uos.unity.cn
技術交流 QQ 群:823878269
公眾號:UOS游戲云服務
Unity 官方微信
第一時間了解Unity引擎動向,學習進階開發技能
每一個“點贊”、“在看”,都是我們前進的動力
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.