[캡스톤디자인] FCM 채팅 푸시 알람 구현 (1)

Dev_Sanizzang·2023년 9월 28일
2

캡스톤디자인

목록 보기
14/15

📕 개요

현재 모임 당 채팅이 한개 씩 존재하는 데 모임에서 채팅이 이뤄지고 있더라도 알 수 있는 방법이 없었다. 고로 모임에서 채팅을 하고 있다면 모임원들에게 채팅 알람을 보내고자한다.

어떻게 구현하면 좋을지 고민 중 Firebase에서 제공하는 FCM이라는 것이 있다는 것을 알게 되었고 이를 통해 채팅 알람을 구현해보고자한다.

🤔 푸시(Push)란?

  • PC 혹은 모바일 디바이스내, 보이는 팝업창을 의미한다.
  • 카카오톡의 대화내용 혹은 마케팅 목적으로 기기에 발송되는 알림을 푸시라고 보면된다.

🖥 FCM (Firebase - Cloud - Messaging)

메세지를 안정적으로 무료 전송할 수 있는 크로스 플랫폼 메시징 솔루션

💡 기존에는 iOS, Android, Web 등의 플랫폼에서 Push 메시지를 보내기 위해서는 각 플랫폼 환경(APNS, GCM)별로 개발해야 하는 불편함이 있었다.
하지만 FCM은 교차 플랫폼 메시지 솔루션이기 때문에 FCM을 이용해서 개발을 진행하면, 플랫폼에 종속되지 않고 Push 메시지를 전송할 수 있다.

  • Firebase의 서비스는 요금 정책에 따라, 이용할 수 있는 범위가 다르지만 FCM은 요금 정책에 구분 없이 무료로 사용하는 것이 가능하다.

🌟 주요 기능

메세지 종류

  • FCM의 메세지 타입은 "알림 메시지"와 "데이터 메시지"로 구분할 수 있다.
  • 알림 메시지: 사용자에게 표시되는 키 모음이 사전 정의되어 있음.
{
  "to": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
  "notification": {
    "body": "great match!",
    "title": "Portugal vs. Denmark",
    "icon": "myicon"
  }
}
  • 데이터 메시지: 맞춤 키-값 쌍만 있음 (사전 정의 된 키 모음 없음)
{
  "to": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
  "notification": {
    "body": "great match!",
    "title": "Portugal vs. Denmark",
    "icon": "myicon"
  }
}
메세지 종류알림 가능 여부알림 저장 개수알림 처리 방법
알림 메시지가능여러 알림을 저장하나, OS 환경마다 다르다.앱이 백그라운드 일 때
데이터 메시지가능1개의 알림만 저장앱이 포그라운드 일 때

🔍 자세한 내용은 FCM 공식문서 FCM 메시지 정보를 확인하자

타겟팅

종류대상수설명
단일 기기1개하나의 기기(앱 기준)
기기 그룹20개알림 키에 허용되는 그룹
주제 구독1000개등록 토큰에 구독된 기기

💡 주제 구독(subscribe)?
STOMP나 Kafka를 사용해봤으면 알겠지만 어떠한 주제를 구독을 해놓으면 해당 주제에 업데이트된 사항이 있다면 해당 주제를 구독한 사람들에게 업데이트 정보를 보내준다.

클라이언트 앱에서 메시지 전송

  • FCM을 이용하면 앱 서버에서 클라이언트 앱으로 다운 스트림 메세지를 보낼 수 있을 뿐만 아니라, 클라이언트 앱에서 앱 서버로도 업 스트림 메세지를 보낼 수 있다.
    -> 클라이언트 앱에서 앱 서버로 업 스트림 메세지를 보내기 위해서는 선행 조건이 필요하다.

👌 푸시 알림을 위한 3가지 구성요소

  • 알림 제공자
    알림 요청(notification request)을 만들어 푸시 알림 서비스(FCM)로 보내주는 주체.
    알림 요청을 만들기 위해서는 다음과 같은 데이터가 필요하다.
    • 단말 토큰 (device token): 알림 요청을 보내는 데 필요한 고유 식별자.
    • 페이로드 (payload): 알림 내용을 담은 JSON 딕셔너리
  • FCM
    구글이 제공하는 원격 서비스. 푸시 알림을 다양한 플랫폼으로 보내는 역할을 담당
  • 디바이스 장치
    푸시 알림을 수신하는 사용자 단말

FCM 클라우드 메시지의 흐름

  • HTTP 프로토콜을 사용할 경우, FCM 클라우드 메시지가 처리되는 과정을 그림으로 나타내보면 다음과 같다.

  1. 앱 서버에서 FCM Backend 서버에 클라이언트 앱에 보내고자 하는 메세지를 담은 정보와, 서버의 인증 정보 클라이언트의 토큰을 담아서 HTTP POST를 요청을 보낸다.
  2. 이것을 FCM Backend 서버는 메시지의 이상 유무에 따라 적절한 응답을 하게 된다.
  3. 이후 FCM Backend 서버에서 여러가지(우선 순위, 앱과의 통신 가능 여부 등등)를 고려하여 실제 클라우드 메시지를 기기로 보내게 된다.
  4. 기기에서는 받은 메시지를 적당히 처리하고 FCM Backend 서버로 응답 메시지를 보내게 된다.

💡 단, 위의 플로우 대로 메시지를 전송하려면 메시지를 수신할 클라이언트는 자신의 정보를 FCM Backend 서버에 등록해야한다.

  • 클라이언트는 자신의 정보(토픽, 디바이스 정보)를 FCM Backend 서버에 등록해야 한다.
  • 메시지를 전송할 주체(앱 서버)는 등록된 정보를 획득해야 하며, 해당 정보로 다운 스트림 메시지를 전송한다.

🔍 신뢰할 수 있는 서버 환경의 요구사항

FCM Backend 서버와 통신을 위한 어플리케이션 서버를 구축하기 위해선 다음 "3가지" 규칙을 지켜야 한다.

  1. FCM Backend 서버에 FCM에서 지정한 형식의 메시지 요청을 보낼 수 있어야 한다.

  2. 지수 백오프를 사용하여 요청을 처리하고 다시 보낼 수 있어야 한다.

    💡 지수 백오프: 요청이 실패할 때마다 다음 요청까지의 유효시간 간격을 n배씩 늘리면서 재요청을 지연시키는 알고리즘
    -> 임의 지연을 사용하여 연쇄 충돌을 방지하기 위해서 사용한다.

  1. 서버 승인 사용자의 인증 정보와 클라이언트의 등록 토큰을 안전하게 저장할 수 있어야 한다.

    💡 서버 승인 사용자의 인증 정보: 메시지를 보낼 앱 서버가 인증된 서버라는 것을 증명하는 정보
    💡 클라이언트의 등록 토큰: 메시지를 보내고자 하는 디바이스의 정보

🔍 FCM Backend 서버와 통신을 위한 앱 서버의 옵션 선택사항

  • FCM Backend 서버와 상호 작용할 방법을 결정해야 한다.

1. Firebase Admin SDK

  • Node.js, Java, Python, C#, Go 등의 프로그래밍 언어 지원.
  • 기기에서 주제 구독 및 구독 취소가 가능하고, 다양한 타켓 플랫폼에 맞는 메세지 페이로드 구성.
  • 나머지 옵션과는 다르게, 초기화 작업만 잘 진행하면 인증 처리를 자동으로 수행한다.
  • FCM에서 가장 권장하는 옵션이다.

2. FCM HTTP v1 API

  • 가장 최신 프로토콜로서 보다 안전한 승인과 유연한 교차 플래솜 메시징 기능 제공

3. 기존의 HTTP 프로토콜

4. XMPP 서버 프로토콜

  • 클라이언트 애플리케이션에서 업스트림 메시징을 사용하려면 이 옵션을 선택해야 한다.
  • 위에서 얘기했던 FCM의 마지막 특징인 업스트림 메시징을 사용하려면, 다른 선택지 없이 이 옵션을 선택해야 한다.

🧐 푸시 메시지 전송 방법

FCM을 이용해 각 유저들에게 푸시메시지를 전송하기 위해선 TOKEN, TOPIC을 활용해 푸시 메시지를 보낼 수 있다.

FCM의 TOKEN

  • 앱이 FCM 서버와 통신하기 위해 사용되는 고유한 식별자
  • 앱은 서버와 통신할 때 토큰을 사용하여 FCM 서버에서 앱을 식별하고, 이를 통해 메시지 전송을 할수 있다.
  • FCM의 토큰은 앱이 설치된 디바이스마다 고유하다. 앱이 설치된 디바이스를 추가하거나 삭제할 때 토큰이 변경될 수 있다. (refresh)
  • 서버는 이러한 FCM 토큰을 사용하여 특정 디바이스에 메시지를 전송할 수 있다.

💡 즉, Token은 Firebase에서 관리하는 프로젝트별 접속하는 기기의 고유 ID로 볼 수 있다.

FCM의 TOPIC

  • 토픽(Topic)은 일종의 채널로서, 이를 통해 일련의 수신자들에게 메시지를 전송할 수 있다.
  • 구독 및 구독취소 요청 시, FCM은 구독한 유저들을 내부적으로 관리한다.
  • subscribe, unsubscribe 메서드를 통해 구독과 구독 취소 요청을 FCM에 전송할 수 있다.
  • 토픽을 통한 푸시 발송시, 토픽을 구독한 사용자들에게 메시지를 전송할 수 있다.

💣 FCM에서 토픽을 선정할 때 유의해야할 사항

  • 토픽의 이름은 알파벳숫자로만 구성되어야 하며, 길이는 최대 256자까지 설정가능하다.
  • 특수문자나 공백은 사용이 불가하다.
  • 토픽 이름은 유일해야한다. 같은 이름의 토픽이 이미 존재하면 새로운 토픽을 생성할 수 없다.

서버가 해야할 모범 사례

  • FCM 공식문서 中

Firebase에서 발급된 토큰의 경우 발급 이후의 토큰관리를 하고있지 않기에, 이를 서버에서 따로 관리를 해줘야 함을 알 수 있다.

이때 토큰 또한, 서버에서 구독 이후 따로 관리를 해줘야 함을 알 수 있다.

푸시 메시지 전송 Code 작성법

메시지 발송 시, FCM에서 제공하는 발송 메서드들은 다음과 같다.

send

  • 하나의 특정 장치로 보내기 위한 메서드로서, 하나의 대상에게 푸시 메시지 요청을 전송할 수 있다.
  • 토큰을 통한 특정 대상 ( 1 : 1 ) 발송도 가능하고 Topic을 포함한 FCM에서의 1:N 발송도 가능하다.

sendMulticast

  • 하나의 메시지에 등록되어 있는 여러명의 유저에게 1:N 발송이 가능하다.
  • 단, 한번의 호출당 1000명 까지 지정이 가능하다.

sendAll

  • 일괄 메시지 전송이 가능하다.
  • 위에서 소개한 sendMulticast는 1:N 발송이라면 sendAll의 경우 N:N 발송이다.
  • 위 메서드도 동일하게 한번의 요청에 1000건까지 가능하다.

특정 기기에 메시지 전송

특정 기기 1개에 메시지를 보내려면 아래와 같이 기기의 등록 토큰을 전달한다.

// This registration token comes from the client FCM SDKs.
String registrationToken = "YOUR_REGISTRATION_TOKEN";

// See documentation on defining a message payload.
Message message = Message.builder()
    .putData("score", "850")
    .putData("time", "2:45")
    .setToken(registrationToken)
    .build();

// Send a message to the device corresponding to the provided
// registration token.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);

여러 기기에 메시지 전송

// Create a list containing up to 500 registration tokens.
// These registration tokens come from the client FCM SDKs.
List<String> registrationTokens = Arrays.asList(
    "YOUR_REGISTRATION_TOKEN_1",
    // ...
    "YOUR_REGISTRATION_TOKEN_n"
);

MulticastMessage message = MulticastMessage.builder()
    .putData("score", "850")
    .putData("time", "2:45")
    .addAllTokens(registrationTokens)
    .build();
BatchResponse response = FirebaseMessaging.getInstance().sendMulticast(message);
// See the BatchResponse reference documentation
// for the contents of response.
System.out.println(response.getSuccessCount() + " messages were sent successfully");

주제(Topic)로 메시지 전송

아까 말했던 특정 주제(Topic)을 구독(subscribe) 했을 때 해당 주제(Topic)을 구독한 사람들에게 메시지를 전달하는 방식이다.

// The topic name can be optionally prefixed with "/topics/".
String topic = "highScores";

// See documentation on defining a message payload.
Message message = Message.builder()
    .putData("score", "850")
    .putData("time", "2:45")
    .setTopic(topic)
    .build();

// Send a message to the devices subscribed to the provided topic.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);

🔍 더 많은 정보는 FCM 공식문서의 보내기 요청 작성을 확인하자.

참고 문서

FCM 공식문서
[Firebase] FCM에 대해서 알아보자.
ZUM 기술블로그 (FCM 푸시 파헤치기)

🚪 마무리

이번 포스팅에서는 채팅 알람을 위한 FCM에 대해 정리해보는 시간을 가져보았다.
다음 포스팅에서는 FCM을 통해 알람을 구현해보는 시간을 가져보겠다.

profile
기록을 통해 성장합니다.

0개의 댓글