본문 바로가기

ios 앱개발

[SWIFT] IOS에서 채팅기능 구현하기(3) with AWS Amplify

반응형

네 접니다.

지난 게시물에 이어서 이번에는 실질적 채팅 기능을 구현하는 방법에 대해 작성하겠습니다.

 

https://pinlib.tistory.com/entry/SWIFT-IOS에서-채팅기능-구현하기2-with-AWS-Amplify

 

[SWIFT] IOS에서 채팅기능 구현하기(2) with AWS Amplify

네, 접니다. 지난 게시물에 이어서 이번에는 실질적 채팅 기능을 구현하는 방법에 대해 작성하겠습니다. https://pinlib.tistory.com/entry/SWIFT-IOS에서-채팅기능-구현하기1-with-AWS-Amplify [SWIFT] IOS에서 채팅

pinlib.tistory.com

 

이전 게시물을 읽어보시고 이번 게시물을 읽어보시는 것을 추천드립니다.

 

이번이 message구현의 마지막 게시물이자 해당 project자체도 마지막 게시물이 될 것 같네요.

이 글이 올라가는 기점으로 제가 aws를 해지할 생각이라서...,

 

뭐 어쨋든 잡설은 치우고 이어서 글을 작성해볼게여

 

0. 변수 선언

각각의 함수를 구현하기에 앞서, 해당 함수를 사용하기 위해서는 아래의 변수들을 선언해야 합니다.

class ChattingViewController: MessagesViewController {
    var otherPerson: String?
    
    var currentUser = Sender(senderId: "self", displayName: "current user")
        
    var otherUser = Sender(senderId: "other", displayName: "other user")
        
    var messages = [MessageType]()
    
    var unique_channel : String!

    var detailData = [String:String]()
    
    var subscription: AmplifyAsyncThrowingSequence<GraphQLSubscriptionEvent<ChatMessage>>?

 

1. InputBarAccessoryViewDelegate

extension ChattingViewController: InputBarAccessoryViewDelegate {
    func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) {
        // Create a new ChatMessage
        
        let email = userGetAuth()
    
        Task{
            if(otherPerson != nil){
                //comment로 들어옴
                let member_channels = try await Amplify.DataStore.query(ChatChannel.self, where: ChatChannel.keys.Member1.eq(email) && ChatChannel.keys.Member2.eq(otherPerson))
                for member_channel in member_channels {
                    unique_channel = member_channel.id
                }
                if(unique_channel != nil){
                    //채팅방 존재의 경우 -> 현재 channel값 이용
                    await saveMessage(unique_channel,email!,text, .normal)
                } else {
                    await addChatRoom(email!, otherPerson!, "dateString", .normal)
                    let member_channel2s = try await Amplify.DataStore.query(ChatChannel.self, where: ChatChannel.keys.Member1.eq(email) && ChatChannel.keys.Member2.eq(otherPerson))
                    
                    for member_channel2 in member_channel2s {
                        unique_channel = member_channel2.id
                    }
                    await saveMessage(unique_channel,email!,text, .normal)
                }
            } else {
                //list view로 들어옴
                unique_channel = detailData["channel"]
                await saveMessage(unique_channel,email!,text, .normal)
            }
        }
        
        inputBar.inputTextView.text.removeAll()
    }
}

 

우선 이전에 소개한 userGetAuth함수로 유저의 이메일 정보를 받아옵니다.

이후, 가져온 email을 이용해 채팅방의 존재 여부(입장경로)를 파악한 후 input_bar에 들어간 text내용을 

saveMessage의 parameter로 사용합니다.

 

여기서 입장경로란

최초로 채팅을 하게 될 경우에는 채널(채팅방)이 따로 생성되어 있지 않으므로 addChatRoom함수를 이용해 채널을 신규 생성해줘야 합니다.

허나, 이미 채널이 존재하면 saveMessage함수를 바로 호출하기만 하면 됩니다.

 

2. saveMessage

    private func saveMessage(_ channel: String, _ sender: String, _ message: String, _ priority: Priority) async {
        do {
            let currentDate = Date()
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "MM-dd HH:mm"
            let dateString = dateFormatter.string(from: currentDate)
            let item = ChatMessage(id: UUID().uuidString, channel: channel, sender: sender, message: message, timestamp: dateString, priority: priority)
            _ = try await Amplify.DataStore.save(item)
        } catch {
            print("Could not save item to dataStore: \(error)")
        }
    }

 

InputBarAccessoryViewDelegate함수에서 parameter로 넘어온 값을 이전에 만든 ChatMessage struct에 담아

AWS Amplify 서버에 메시지를 저장해줍니다.

 

3. addChatRoom

    private func addChatRoom(_ member1: String, _ member2: String, _ dateString: String,_ priority: Priority) async {
        
        do{
            let userEmail = userGetAuth()
            let item = ChatChannel(id: UUID().uuidString, Member1: userEmail!,  Member2: member2, Date: dateString, priority: priority)
            
            _ = try await Amplify.DataStore.save(item)
            print(dateString)
        } catch {
            print("Could not save item to dataStore: \(error)")
        }
    }
}

 

해당 함수의 경우, InputBarAccessoryViewDelegate에서 채널이 없을 경우 호출하게 되며

새롭게 채널(채팅방)을 생성하게 됩니다.

 

4. readMessage

    private func readMessage(_ noticeNumber: String) async {
        do {
            let email = userGetAuth()
            currentUser.senderId = email!
            let myinfos = try await Amplify.DataStore.query(User.self, where: User.keys.id.eq(email))
            for myinfo in myinfos {
                currentUser.displayName = myinfo.UserNickName
            }
            
            if(detailData["member2"] != nil){
                otherUser.senderId = detailData["member2"]!
                let yourinfos = try await Amplify.DataStore.query(User.self, where: User.keys.id.eq(detailData["member2"]))
                for yourinfo in yourinfos {
                    otherUser.displayName = yourinfo.UserNickName
                }
            }
            
            if(otherPerson != nil){
                //comment로 들어옴
                otherUser.senderId = otherPerson!
                let yourinfos = try await Amplify.DataStore.query(User.self, where: User.keys.id.eq(otherPerson))
                for yourinfo in yourinfos {
                    otherUser.displayName = yourinfo.UserNickName
                }
            }
            
            let awsMessages = try await Amplify.DataStore.query(ChatMessage.self, where: ChatMessage.keys.channel.eq(unique_channel))
            
            for awsMessage in awsMessages {
                if(awsMessage.sender == email){
                    //내꺼
                    messages.append(Message(sender: currentUser,
                                            messageId: awsMessage.id,
                                            sentDate: Date().addingTimeInterval(-86400),
                                            kind: .text(awsMessage.message),
                                            channel: awsMessage.channel))
                } else {
                    //니꺼
                    messages.append(Message(sender: otherUser,
                                            messageId: awsMessage.id,
                                            sentDate: Date().addingTimeInterval(-86400),
                                            kind: .text(awsMessage.message),
                                            channel: awsMessage.channel))
                }
            }
        } catch {
            print("Could not query DataStore: \(error)")
        }
    }

 

AWS Amplify에 저장된 메시지(데이터)를 채팅창으로 불러오는 함수입니다.

여기서는 이전에 만든 message struct를 이용합니다.

 

5. AWS Amplify Real-time

이제 AWS Amplifty의 Real-time을 구현해야 합니다.

메시지를 전송하고 받을 때 마다, 서버로 부터 데이터를 받아오는 즉, 갱신과정의 코드입니다.

 

아래는 subscription 함수입니다.

    func createSubscription() async{
        if let subscription = subscription {
            Task {
                do {
                    for try await subscriptionEvent in subscription {
                        switch subscriptionEvent {
                        case .connection(let subscriptionConnectionState):
                            print("Subscription connect state is \(subscriptionConnectionState)")
                        case .data(let result):
                            switch result {
                            case .success(let createdTodo):
                                print("Successfully got todo from subscription: \(createdTodo)")
                            case .failure(let error):
                                print("Got failed result with \(error.errorDescription)")
                            }
                        }
                    }
                } catch {
                    print("Subscription has terminated with \(error)")
                }
            }
        } else {
            print("Subscription is nil")
        }
    }
    
    //real-time unsubscribtion
    func cancelSubscription() {
        // Cancel the subscription listener when you're finished with it
        subscription?.cancel()
    }

 

이렇게 저의 Luvky 프로젝트의 장례식이 마무리 되었습니다.

 

사실 더 많은 코드들을 소개 할 계획이었는데,

이제는 꼴도 보기 싫어서 좀 빠르게 마무리한 감이 있네요.

 

요즘 생각이 좀 많았습니다.

근본적으로 해야 할 일들이 생기다 보니,

셀프 가스라이팅에 걸려서 하고 싶은 일도 바뀌고

다른 공부를 해야되더라구요

 

글의 주제가 이제 또 바뀔 수도 있습니다.

그래도 어차피 맥북도 있으니깐 소규모 프로젝트로 해보고 싶은거 앱형식으로 간단히 만들 꺼 같기는 합니다.

 

다음 게시물은 제 추측으로는 첫 해외 여행인 홍콩여행이 될 거 같습니다.

사실 갔다온지 좀 되긴 했는데...,

 

모르겠습니다.

 

하고 싶은 일이 바꼈는데

공부는 못하고 있고, 그냥 처리해야 될 이상한 일들만 생긴다.

잘 모르겠다

 

담배나 삐리삐리빠라뽕하러 갈게염

수고염

 

반응형