이슈
특정 액션이 있을 때마다 특정 사용자에게 푸시 알림을 보내고 싶다. 어떻게 구현할 수 있을까?
해결
라이브러리
FCM
Firebase
에서 Firebase Cloud Message, 일명 FCM
이라는 서비스로 Android/iOS 애플리케이션에 대한 푸시 알림 서비스를 지원하고 있다. 푸시 알림의 대상은 다음과 같은 옵션들로 지정할 수 있다.
- 전체 사용자
- 특정 그룹의 사용자
- 특정 사용자
또한 이러한 대상들에 대하여 시간을 예약하거나 알림을 보낼 수도 있고 특정 액션이 있을 때마다 전송할 수도 있다. 본 포스트에서는 특정 사용자에게 특정 액션이 발생할 때 푸시 알림을 보낼 것이다.
푸시 알림 요청은 클라이언트 단에서 Firebase Console
로 보낼 수도 있고, 자체 개발 서버가 있다면 서버로 API
요청을 한 후, 서버에서 firebase admin
라이브러리를 통해 푸시 알림을 보내는 방식이 있다.
FCM
을 사용하려면 Android
및 iOS
별로 사용하는 플랫폼에 따라 Firebase Console
에 접속하여 프로젝트 내에 설정해주어야 할 사항이 있다. 이 내용은 Firebase Console
에서 쉽게 확인할 수 있고 정리된 타 블로그 포스트들도 많으므로 생략한다. 그리고 본 포스트에서는 Android
플랫폼에서의 구현과 설명을 주로 한다.
코드
1 |
|
위 코드는 FCM
관련 초기 설정을 하는 코드로, 앱 구동 시에 맨 앞 단에서 실행시켜줘야 한다. 그런데 요러한 초기 세팅 코드는 다양한 블로그나 심지어 공식 FCM
사이트에서도 관련 내용을 살펴볼 수 있는데 하나같이 오류가 나거나 제대로 적용이 안됐다. Flutter
에서 FCM
은 아직도 업데이트가 활발한 듯 하다. 우선 flutter 2.2.3
버전 기준으로 위 코드를 그대로 복붙만 해도 백엔드 단의 코드 작성만 완료해주면 foreground
와 background
에서 성공적으로 푸시 알림을 수신할 수 있다.
고찰
Background vs Foreground
앱을 통해 기기에 푸시 알림이 오는 상황을 다음과 같이 두 가지로 구분할 수 있다.
- 해당 앱이
foreground
로 실행 중일 때 - 해당 앱이
background
로 실행 중이거나 꺼져있을 때
위 두 가지 사항에 대하여 FCM
은 각기 다른 핸들러를 적용한다. 이 때 background
상황이나 꺼져있는 상황에서는 별도의 핸들러를 구현하지 않고 FCM
의 initializing
만 해줘도 푸시 알림을 수신할 수 있다. 그런데 foreground
의 경우, 즉 앱이 기기 화면의 최상단에서 실행 중일 경우 별도의 핸들러를 구현하고 라이브러리를 사용해야 한다.
다만 foreground
에서의 경우 또 한가지 특징이 있는데, 바로 알림의 중요도이다. Android
에서는 내부적으로 다음과 같은 푸시 알림 정책을 갖고 있다.
앱이 foreground일 때는 이미 앱을 사용하고 있으니 굳이 알림을 안보내도 되겠다!
이 때 알림의 중요도를 MAX로 설정해주면 내부적으로 위와 같은 정책의 예외 사항으로 보고 앱이 foreground
인 상황에서도 정상적으로 푸시 알림을 화면과 상단바 알림에 표시해준다.
Flutter Local Notifications
이 라이브러리는 다양한 플랫폼 별로 푸시 알림을 띄워주는 라이브러리이다. Android
와 iOS
는 물론, Windows
, Linux
, MacOS
와 같은 desktop 기반 OS도 지원한다! Foreground
에서의 푸시 알림 수신에서 본 라이브러리를 사용해 알림을 표시해준다. 알림의 제목과 내용, 아이콘을 설정할 수 있으며 자세한 설정 방법은 위 코드에서 확인하거나 공식 문서에서 확인할 수 있다.
Firebase Token
그렇다면 어떻게 사용자 또는 기기를 특정할 수 있을까? 바로 firebase token
을 사용한다. 이 토큰의 특징은 다음과 같다.
- 기기 별로 토큰이 발급된다
- 앱을 재설치하거나 업데이트할 경우 토큰 값이 변경된다
- 만료 기간이 있으며 refresh 가능하다
토큰이 기기 별로 발급된다고 했는데, 사실상 동일 기기에서 같은 패키지명을 갖는 앱을 여러개 설치할 순 없으므로 앱 당 발급된다고 봐도 무방하다. 즉, 앱 내에서의 서비스 계정에 따라 발급하는 토큰이 아님에 주의한다.
따라서 앱 최초 실행 시에 firebase token
을 발급하고 서버로 전달하여 DB
상에서 사용자 계정과 연결해주어야 한다. 이 때 토큰은 앱을 지웠다 깔거나 만료 기간이 되었을 때 갱신되는데, 토큰이 만료되면 firebase
에 그에 따른 refresh
요청을 따로 보내지 않아도 이후부터 알아서 갱신된 토큰으로 발급해준다. 따라서 위 코드와 같이 매 번 앱 실행 시마다 앞 단에서 FCM
세팅을 함과 동시에 firebase token
을 갱신해주는 것도 한 가지 방법이다. 앱 실행 시마다 네트워크 통신을 하는 것이 부담스럽다면 Flutter Secure Storage
와 같은 보안 내부 저장소에 토큰을 저장해둘 수도 있다. 다만 토큰 갱신이 제 때 이루어지지 않아 푸시 알림의 누락이 발생할 수도 있다.