IVS Chat Client Messaging iOS SDK 사용 - Amazon IVS

IVS Chat Client Messaging iOS SDK 사용

이 문서에서는 Amazon IVS Chat Client Messaging iOS SDK 사용과 관련된 단계를 안내합니다.

채팅 룸에 연결

시작하기 전에 Amazon IVS Chat 시작하기의 내용을 숙지해야 합니다. 또한 , AndroidiOS에 대한 예제 앱도 참조하세요.

채팅 룸에 연결하려면 앱에 백엔드에서 제공한 채팅 토큰을 검색할 수 있는 방법이 필요합니다. 애플리케이션은 아마도 백엔드에 대한 네트워크 요청을 사용하여 채팅 토큰을 검색할 것입니다.

가져온 채팅 토큰을 SDK와 통신하려면 SDK의 ChatRoom 모델에서 async 함수 또는 초기화 시점에서 제공된 ChatTokenProvider 프로토콜을 따르는 객체의 인스턴스를 제공해야 합니다. 이러한 메서드 중 하나에서 반환되는 값은 SDK의 ChatToken 모델의 인스턴스여야 합니다.

참고: 백엔드에서 검색된 데이터를 사용하여 ChatToken 모델의 인스턴스를 채웁니다. ChatToken 인스턴스의 초기화에 필요한 필드는 CreateChatToken 응답의 필드와 동일합니다. ChatToken 모델의 인스턴스 초기화에 대한 자세한 내용은 ChatToken의 인스턴스 생성을 참조하세요. 백엔드에서 앱에 대한 CreateChatToken 응답의 데이터를 제공해야 합니다. 채팅 토큰을 생성하기 위해 백엔드와 통신하는 방법은 앱과 인프라에 따라 달라집니다.

ChatToken을 SDK로 제공하는 방법을 선택한 후, 백엔드에서 연결하려는 채팅 룸을 생성하는 데 사용한 토큰 공급자와 AWS 리전으로 ChatRoom 인스턴스를 초기화하고 .connect()를 호출합니다. .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의 인스턴스 생성

SDK에 제공된 이니셜라이저를 사용하여 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 )

Decodable 사용

IVS Chat API와 인터페이스하는 동안 백엔드에서 프런트엔드 애플리케이션으로 CreateChatToken 응답을 전달하기로 결정한 경우 ChatToken의 Swift Decodable 프로토콜 준수를 활용할 수 있습니다. 하지만 한 가지 문제가 있습니다.

CreateChatToken 응답 페이로드는 ISO 8601 인터넷 타임스탬프 표준을 사용하여 형식이 지정된 날짜 문자열을 사용합니다. 일반적으로 Swift에서 JSONDecoder.DateDecodingStrategy.iso8601JSONDecoder.dateDecodingStrategy속성에 대한 값으로 제공합니다. 하지만 CreateChatToken은 문자열에 고정밀 분수 초를 사용하며, 이는 JSONDecoder.DateDecodingStrategy.iso8601에서 지원되지 않습니다.

편의를 위해 SDK는 JSONDecoder.DateDecodingStrategy에 대한 공개 확장 프로그램에 ChatToken의 인스턴스를 디코딩할 때 성공적으로 JSONDecoder를 사용할 수 있도록 하는 추가 .preciseISO8601 전략을 제공합니다.

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에 빌드하려는 경우 SDK는 채팅 룸의 연결 상태가 변경될 때 알림을 받는 두 가지 방법으로 Combine 또는 ChatRoomDelegate 사용을 제공합니다. 아래에서 설명합니다.

중요: 네트워크 연결 끊어짐 등으로 인해 채팅 룸의 연결 상태도 변경될 수 있습니다. 앱을 빌드할 때 이 점을 고려하세요.

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:)를 호출하고, SDK에서 제공된 ChatRequest 객체 중 하나의 인스턴스를 전달합니다. 지원되는 요청은 Request.swift입니다.

채팅 룸의 일부 작업을 수행하려면 백엔드 애플리케이션이 CreateChatToken을 호출할 때 연결된 사용자에게 특정 기능을 부여해야 합니다. 설계상 SDK는 연결된 사용자의 기능을 식별할 수 없습니다. 따라서 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!" ) )

위에서 언급한 바와 같이 room.perform(request:)ChatRoom에서 ChatMessage를 수신하면 반환됩니다. 요청에 문제가 있는 경우(예: 룸의 메시지 문자 제한 초과) 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) }

메시지에 메타데이터 추가

메시지를 보낼 때 관련 메타데이터를 추가할 수 있습니다. SendMessageRequest에는 attributes 속성이 있고, 이 속성을 사용하여 요청을 초기화할 수 있습니다. 첨부한 데이터는 다른 사람들이 채팅 룸에서 해당 메시지를 받을 때 메시지에 첨부됩니다.

다음은 보내는 메시지에 이모트 데이터를 첨부하는 예시입니다.

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 페이로드는 매우 유연하고 강력합니다. 이를 사용하여 다른 방법으로는 할 수 없는 메시지 관련 정보를 도출하세요. 예를 들어 메시지 문자열을 구문 분석하여 이모트 등의 정보를 가져오는 것보다 속성을 사용하는 것이 훨씬 쉽습니다.

메시지 삭제

채팅 메시지를 삭제하는 것은 메시지를 보내는 것과 같습니다. ChatRoom에서 room.perform(request:) 함수를 호출하고 DeleteMessageRequest의 인스턴스를 생성하면 됩니다.

받은 챗 메시지의 이전 인스턴스에 쉽게 액세스하려면 DeleteMessageRequest의 이니셜라이저로 message.id의 값을 전달합니다.

필요한 경우 UI에 표시할 수 있도록 이유 문자열을 DeleteMessageRequest에 제공합니다.

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) }