使用 IVS 聊天功能用戶端傳訊 iOS SDK - Amazon IVS

使用 IVS 聊天功能用戶端傳訊 iOS SDK

本文件將逐步介紹使用 Amazon IVS 聊天功能用戶端訊息 iOS SDK 時涉及的步驟。

與聊天室連線

在開始使用之前,請先熟悉 Amazon IVS 聊天功能入門。另請參閱 Web 版、Android 版和 iOS 版的範例應用程式。

若要與聊天室連線,您的應用程式必須設法擷取後端提供的聊天權杖。您的應用程式可能會向後端發出網路請求以擷取聊天權杖。

若要將此擷取的聊天權杖傳送給開發套件,開發套件的 ChatRoom 模型會要求您提供符合在初始化時所提供 ChatTokenProvider 通訊協定的 async 函數或物件執行個體。這些方法中的任何一種傳回的值都必須是開發套件 ChatToken 模型的執行個體。

注意:請使用從後端擷取的資料來填入 ChatToken 模型的執行個體。初始化 ChatToken 執行個體所需的欄位與 CreateChatToken 回應中的欄位相同。如需有關初始化 ChatToken 模型執行個體的詳細資訊,請參閱建立 ChatToken 執行個體。請謹記,您的後端必須負責向應用程式提供 CreateChatToken 回應中的資料。您用來與後端通訊以產生聊天權杖的方式取決於您的應用程式及其基礎架構。

選擇向開發套件提供 ChatToken 的策略之後,請在使用您的權杖提供者,以及您的後端用來建立所嘗試連線之聊天室的 AWS 區域,成功初始化 .connect() 執行個體後呼叫 ChatRoom。請注意,.connect() 是一個擲回非同步函數:

import AmazonIVSChatMessaging let room = ChatRoom( awsRegion: <region-your-backend-created-the-chat-room-in>, tokenProvider: <your-chosen-token-provider-strategy> ) try await room.connect()

符合 ChatTokenProvider 通訊協定

如果使用 ChatRoom 的初始設定式中的 tokenProvider 參數,則可提供 ChatTokenProvider 的執行個體。以下為符合 ChatTokenProvider 的物件範例:

import AmazonIVSChatMessaging // This object should exist somewhere in your app class ChatService: ChatTokenProvider { func getChatToken() async throws -> ChatToken { let request = YourApp.getTokenURLRequest let data = try await URLSession.shared.data(for: request).0 ... return ChatToken( token: String(data: data, using: .utf8)!, tokenExpirationTime: ..., // this is optional sessionExpirationTime: ... // this is optional ) } }

接著您可取得此符合物件的執行個體,並將其傳給 ChatRoom 的初始設定式:

// This should be the same AWS Region that you used to create // your Chat Room in the Control Plane let awsRegion = "us-west-2" let service = ChatService() let room = ChatRoom( awsRegion: awsRegion, tokenProvider: service ) try await room.connect()

提供 Swift 非同步函數

假設您已有一個用於管理應用程式網路請求的管理工具。這看起來類似下述:

import AmazonIVSChatMessaging class EndpointManager { func getAccounts() async -> AppUser {...} func signIn(user: AppUser) async {...} ... }

您可在管理工具中新增另一個函數,以便從後端擷取 ChatToken

import AmazonIVSChatMessaging class EndpointManager { ... func retrieveChatToken() async -> ChatToken {...} }

然後,在初始化 ChatRoom 時,在 Swift 中使用對該函數的參考:

import AmazonIVSChatMessaging let endpointManager: EndpointManager let room = ChatRoom( awsRegion: endpointManager.awsRegion, tokenProvider: endpointManager.retrieveChatToken ) try await room.connect()

建立 ChatToken 執行個體

使用開發套件中提供的初始設定式可輕鬆建立 ChatToken 執行個體。請參閱 Token.swift 中的文件,以進一步了解 ChatToken 中的屬性。

import AmazonIVSChatMessaging let chatToken = ChatToken( token: <token-string-retrieved-from-your-backend>, tokenExpirationTime: nil, // this is optional sessionExpirationTime: nil // this is optional )

使用可解碼

如果在與 IVS Chat API 對接時,您的後端決定只將 CreateChatToken 回應轉送至您的前端應用程式,則您可利用 ChatToken 符合 Swift Decodable 通訊協定的優勢。但有個必須注意的地方。

CreateChatToken 回應承載會使用以網際網路時間戳記的 ISO 8601 標準格式化的日期字串。通常,在 Swift 中您會提供 JSONDecoder.DateDecodingStrategy.iso8601 作為 JSONDecoder.dateDecodingStrategy 屬性值。但是,CreateChatToken 在其字串中使用的高精確度小數秒數並不受 JSONDecoder.DateDecodingStrategy.iso8601 支援。

為了方便起見,開發套件在 JSONDecoder.DateDecodingStrategy 中提供了公有擴充功能,其額外的 .preciseISO8601 策略可讓您成功使用 JSONDecoder 來解碼 ChatToken 的執行個體:

import AmazonIVSChatMessaging // The CreateChatToken data forwarded by your backend let responseData: Data let decoder = JSONDecoder() decoder.dateDecodingStrategy = .preciseISO8601 let token = try decoder.decode(ChatToken.self, from: responseData)

中斷與聊天室的連線

若要手動中斷您已成功連線的 ChatRoom 執行個體之連線,請呼叫 room.disconnect()。預設情況下,聊天室會在解除配置時自動呼叫此函數。

import AmazonIVSChatMessaging let room = ChatRoom(...) try await room.connect() // Disconnect room.disconnect()

接收聊天訊息/事件

若要在聊天室中傳送和接收訊息,則在您成功初始化 ChatRoom 的執行個體並呼叫 room.connect() 之後,必須提供符合 ChatRoomDelegate 通訊協定的物件。使用 UIViewController 的典型範例如下:

import AmazonIVSChatMessaging import Foundation import UIKit class ViewController: UIViewController { let room: ChatRoom = ChatRoom( awsRegion: "us-west-2", tokenProvider: EndpointManager.shared ) override func viewDidLoad() { super.viewDidLoad() Task { try await setUpChatRoom() } } private func setUpChatRoom() async throws { // Set the delegate to start getting notifications for room events room.delegate = self try await room.connect() } } extension ViewController: ChatRoomDelegate { func room(_ room: ChatRoom, didReceive message: ChatMessage) { ... } func room(_ room: ChatRoom, didReceive event: ChatEvent) { ... } func room(_ room: ChatRoom, didDelete message: DeletedMessageEvent) { ... } }

在連線變更時收到通知

正常而言,在聊天室完全連線之前,您無法在聊天室中執行傳送訊息等動作。SDK 的架構嘗試鼓勵透過非同步 API 在背景執行緒上連線至 ChatRoom。如果您想要在 UI 中建構可停用傳送訊息按鈕等功能,開發套件對此提供兩種使用 CombineChatRoomDelegate 的策略,以便在聊天室的連線狀態變更時收到通知。這些策略說明如下。

重要:聊天室的連線狀態也可能因網路連線中斷等因素而變更。建構應用程式時請將此列入考量。

使用 Combine

ChatRoom 的每個執行個體都會以 state 屬性的形式隨附它自己的 Combine 發佈者:

import AmazonIVSChatMessaging import Combine var cancellables: Set<AnyCancellable> = [] let room = ChatRoom(...) room.state.sink { state in switch state { case .connecting: let image = UIImage(named: "antenna.radiowaves.left.and.right") sendMessageButton.setImage(image, for: .normal) sendMessageButton.isEnabled = false case .connected: let image = UIImage(named: "paperplane.fill") sendMessageButton.setImage(image, for: .normal) sendMessageButton.isEnabled = true case .disconnected: let image = UIImage(named: "antenna.radiowaves.left.and.right.slash") sendMessageButton.setImage(image, for: .normal) sendMessageButton.isEnabled = false } }.assign(to: &cancellables) // Connect to `ChatRoom` on a background thread Task(priority: .background) { try await room.connect() }

使用 ChatRoomDelegate

您也可以在符合 ChatRoomDelegate 的物件中使用可選函數 roomDidConnect(_:)roomIsConnecting(_:) 以及 roomDidDisconnect(_:)。以下為使用 UIViewController 的範例:

import AmazonIVSChatMessaging import Foundation import UIKit class ViewController: UIViewController { let room: ChatRoom = ChatRoom( awsRegion: "us-west-2", tokenProvider: EndpointManager.shared ) override func viewDidLoad() { super.viewDidLoad() Task { try await setUpChatRoom() } } private func setUpChatRoom() async throws { // Set the delegate to start getting notifications for room events room.delegate = self try await room.connect() } } extension ViewController: ChatRoomDelegate { func roomDidConnect(_ room: ChatRoom) { print("room is connected!") } func roomIsConnecting(_ room: ChatRoom) { print("room is currently connecting or fetching a token") } func roomDidDisconnect(_ room: ChatRoom) { print("room disconnected!") } }

在聊天室中執行動作

不同的使用者擁有可在聊天室中執行各種動作所需的不同功能;例如傳送訊息、刪除訊息或中斷使用者連線。若要執行這些動作之一,請在連線的 ChatRoom 上呼叫 perform(request:),並傳入開發套件中提供的其中一個 ChatRequest 物件的執行個體。支援的請求位於 Request.swift 中。

當後端應用程式呼叫 CreateChatToken 時,連線的使用者必須具備授予他們的特定功能,才能在聊天室中執行某些動作。開發套件在設計上無法辨別連線使用者的功能。因此,雖然您可以試著在連線的 ChatRoom 執行個體中執行仲裁者動作,但控制平面 API 最終會決定該動作是否成功。

經由 room.perform(request:) 的所有動作都會等待,直至聊天室收到與所接收模型和請求物件的 requestId 皆相符的預期模型 (其類型與請求物件本身相關) 執行個體。如果請求有問題,ChatRoom 一律會以 ChatError 形式擲回錯誤。ChatError 的定義請見 Error.swift

傳送訊息

若要傳送聊天訊息,請使用 SendMessageRequest 執行個體:

import AmazonIVSChatMessaging let room = ChatRoom(...) try await room.connect() try await room.perform( request: SendMessageRequest( content: "Release the Kraken!" ) )

如上所述,ChatRoom 一收到對應的 ChatMessage,就會傳回 room.perform(request:)。如果請求有問題 (例如超出聊天室的訊息字元限制),就會改為擲回 ChatError 的執行個體。然後,您就可以在 UI 中顯示此實用資訊:

import AmazonIVSChatMessaging do { let message = try await room.perform( request: SendMessageRequest( content: "Release the Kraken!" ) ) print(message.id) } catch let error as ChatError { switch error.errorCode { case .invalidParameter: print("Exceeded the character limit!") case .tooManyRequests: print("Exceeded message request limit!") default: break } print(error.errorMessage) }

將中繼資料附加至訊息

傳送訊息時可附加與該訊息相關的中繼資料。SendMessageRequestattributes 屬性,使用這個屬性可以初始化您的請求。當其他人在聊天室中收到該訊息時,也會連帶收到您附加在訊息中的資料。

以下是將表情符號資料附加在要傳送之訊息中的範例:

import AmazonIVSChatMessaging let room = ChatRoom(...) try await room.connect() try await room.perform( request: SendMessageRequest( content: "Release the Kraken!", attributes: [ "messageReplyId" : "<other-message-id>", "attached-emotes" : "krakenCry,krakenPoggers,krakenCheer" ] ) )

SendMessageRequest 中使用 attributes 對於在聊天產品中建構複雜功能非常有用。例如,在 SendMessageRequest 中使用 [String : String] 屬性字典可以建構執行緒功能!

attributes 承載非常靈活及強大。使用它可衍生您無法以其他方式衍生的訊息相關資訊。例如,使用屬性比剖析訊息字串以取得表情符號等相關資訊要容易得多。

刪除訊息

刪除聊天訊息的方式跟傳送聊天訊息一樣。為了達到此目的,可使用 ChatRoomroom.perform(request:) 函數來建立 DeleteMessageRequest 的執行個體。

若要輕鬆存取已接收之聊天訊息的先前執行個體,將 message.id 的值傳入 DeleteMessageRequest 的初始設定式中。

您也可以向 DeleteMessageRequest 提供原因字串,以便將其顯示在您的 UI 中。

import AmazonIVSChatMessaging let room = ChatRoom(...) try await room.connect() try await room.perform( request: DeleteMessageRequest( id: "<other-message-id-to-delete>", reason: "Abusive chat is not allowed!" ) )

由於這是仲裁者才能做的動作,因此您的使用者實際上可能無法刪除其他使用者的訊息。如果使用者試圖在權限不足的情況下刪除訊息,則您可使用 Swift 的可擲回函數機制在 UI 中顯示錯誤訊息。

當後端叫用 CreateChatToken 供呼叫者使用時,它必須將 "DELETE_MESSAGE" 傳入 capabilities 欄位,才能啟動該功能供已連線的聊天使用者使用。

以下是在功能不足的情況下試圖刪除訊息時發生權限錯誤的範例:

import AmazonIVSChatMessaging do { // `deleteEvent` is the same type as the object that gets sent to // `ChatRoomDelegate`'s `room(_:didDeleteMessage:)` function let deleteEvent = try await room.perform( request: DeleteMessageRequest( id: "<other-message-id-to-delete>", reason: "Abusive chat is not allowed!" ) ) dataSource.messages[deleteEvent.messageID] = nil tableView.reloadData() } catch let error as ChatError { switch error.errorCode { case .forbidden: print("You cannot delete another user's messages. You need to be a mod to do that!") default: break } print(error.errorMessage) }

中斷與其他使用者的連線

使用 room.perform(request:) 可中斷其他使用者與聊天室的連線。明確來說,請使用 DisconnectUserRequest 的執行個體。ChatRoom 收到的全部 ChatMessage 都會有 sender 屬性,其中包含正確初始化 DisconnectUserRequest 執行個體時需要使用的使用者 ID。您也可以在收到中斷連線請求時輸入原因字串。

import AmazonIVSChatMessaging let room = ChatRoom(...) try await room.connect() let message: ChatMessage = dataSource.messages["<message-id>"] let sender: ChatUser = message.sender let userID: String = sender.userId let reason: String = "You've been disconnected due to abusive behavior" try await room.perform( request: DisconnectUserRequest( id: userID, reason: reason ) )

由於這是仲裁者動作的另一個範例,您可以試著中斷其他使用者的連線,但前提是您必須有 DISCONNECT_USER 功能。當您的後端應用程式呼叫 CreateChatToken 並將 "DISCONNECT_USER" 字串注入 capabilities 欄位時,就會設定此功能。

如果您的使用者沒有中斷其他使用者連線的功能,room.perform(request:) 會擲回一個ChatError 執行個體,就像其他請求一樣。檢查錯誤的 errorCode 屬性可以判斷該請求失敗的原因是否因為缺少仲裁者權限:

import AmazonIVSChatMessaging do { let message: ChatMessage = dataSource.messages["<message-id>"] let sender: ChatUser = message.sender let userID: String = sender.userId let reason: String = "You've been disconnected due to abusive behavior" try await room.perform( request: DisconnectUserRequest( id: userID, reason: reason ) ) } catch let error as ChatError { switch error.errorCode { case .forbidden: print("You cannot disconnect another user. You need to be a mod to do that!") default: break } print(error.errorMessage) }