[Flutter & FCM] 단체 톡방 채팅 알림 구현하기

2 분 소요

FCM(Firebase Cloud Messaging) 에는 두 가지 메시지를 보낼 수 있는 방법이 있다.

  • Token 방식
    • 각 User마다 개인의 token을 가지고 있고 알림을 보낼 대상의 token을 구해 전송한다.
  • Topic 방식
    • pub, sub 방식
    • 키 값에 구독을 걸어 놓는다. 누군가 그 키에 알림을 보낼 경우 키에 구독된 모든 대상에게 알림을 전송한다.

처음 개발 당시 단체 톡방을 구현해야 했기 때문에 당연하게 Topic 방식을 선택했었다.

  • 보내야할 대상들을 직접 찾지 않아도 알아서 구독을 한 인원들에게 메시지가 전송된다.
    • token 방식의 단점
    • 단톡방 구현을 위해 방에 있는 모든 인원들의 token을 알아야 한다.

Topic 방식의 문제점 : 내가 보낸 메시지가 나한테도 알림이 옴

하지만 Topic 방식을 구현하고 문제가 발생했다.

image

채팅방을 생성하거나 입장할 때 채팅방을 구독한 상태로 들어오게 된다.

내가 만약 메시지를 보낸다면 키를 통해 알림이 왔음을 FCM은 인식하고 구독한 사람들에게 모두 전달한다.

나도 구독한 사람들 중 한 명이기 때문에 나한테도 내가 쓴 메시지가 들어온다.


방법 1

그렇다면 내가 구독하지 않고 나를 제외한 방인원을 묶는 키를 만들면 되지 않을까란 생각을 하였다.

하지만 이 또한 방의 인원 수 만큼 키의 개수가 발생한다.

방마다 3~5개의 키를 만들어서 관리하는 것은 비효율적이라 생각하고 구독이나 구독취소할 때 발생하는 에러 발생률이 상승할 것이라 예상하였다.

Token 방식 전환

그래서 Token 방식의 전환을 고려하였다.

기존에 생각한 문제점이었던 “단톡방 구현을 위해 방에 있는 모든 인원들의 token을 알아야 한다.” 에 대해서 생각해보았다.

방에 있는 모든 인원들의 token을 알아야 하는 게 왜 문제일까

우선 모든 유저의 token은 회원가입시 DB에 user table에 저장하였다.

그렇다면 모든 인원들의 token을 알기 위해 방에 있는 사람들의 user id를 활용해 token을 가져온다.

DB 접근이 사람의 인원 수 만큼 N번 일어나는 것이다.

게다가 방의 인원은 자유롭게 퇴장과 입장이 가능하기 때문에 메시지를 보낼 때마다 누구에게 보내야 하는지 확인한다.

⇒ DB read의 수가 너무 많아지는 것이 문제이다…

LocalStorage의 도입

DB와 데이터를 주고받는 횟수를 줄이기 위해 캐시 역할로 로컬 스토리지를 도입

Flutter의 SharedPreferences api를 사용해서 휴대폰 내 로컬 스토리지를 무료로 사용할 수 있다.

이 곳에 groupId를 키로 방 인원의 token들을 배열로 저장하여

한번 DB에서 저장했을 때 다음 메시지를 보낼 때는 로컬 스토리지에서 찾고 만약 로컬 스토리지에 해당 groupId가 없다면 DB에서 불러오는 방식을 적용한다.

알고리즘

방입장과 퇴장에 있어 로컬 스토리지를 업데이트 해주는 로직이 필요하다.

그래서 로직을 정리해보자면

  1. 첫 방 입장시 또는 본인이 방을 생성시 DB에서 현재 방에 있는 인원들의 token을 로컬 스토리지에 저장한다.
  2. 만약 누군가 방에 추가로 입장시 로컬 스토리지에 추가하여 업데이트 한다
    • 방에 입장했는지는 메시지 type으로 확인한다.
  3. 누군가 방을 퇴장했다면 그 사람에게 메시지가 가지 않아야 하기 때문에 로컬 스토리지에 삭제하여 업데이트 한다.
    • 마찬가지로 메시지 type으로 누가 퇴장했고 퇴장 메시지를 확인한다.
  4. 본인이 퇴장한다면 더 이상 사용하지 않는 groupId의 로컬스토리지는 삭제한다.

image 1

코드

https://github.com/Han-Bab/HanBab/commit/139872e8a4d94de6e364c7e03f7968a4a9ca653f

카테고리:

업데이트: