코딩마을방범대
[FCM] FCM 토큰의 관리 방법 본문
FCM 토큰은 정해진 수명이나 갱신 주기가 없다.
따라서, 시간과 관계 없이 아래 이벤트가 발생하지 않는다면 만료가 되지 않는다.
- 앱이 인스턴스 ID를 삭제한 경우
- 앱이 새 기기에서 복원되었을 경우
- 사용자가 앱을 제거 / 재설치한 경우
- 사용자가 앱 데이터를 지운 경우
* AOS : onTokenRefresh()
* IOS : messaging:didReceiveRegistrationToken
* WEB : onTokenRefresh
위 메소드들은 토큰이 갱신될 때마다 호출된다.
위와 같은 상황에 해야할 동작이 있다면 해당 메소드를 활용하면 된다.
※ 이제 onTokenRefresh() 대신 MyFirebaseMessagingService 를 상속받아 onNewToken()로 사용한다고 한다
고려할 부분
1. 같은 기기에서 다른 아이디를 쓰는 경우
- 로그아웃 시점에 서버에서 유저 토큰을 삭제
2. 같은 아이디로 여러 기기를 쓰는 경우
- 하나의 유저가 여러 토큰을 보유할 수 있도록 데이터베이스 구성
3. 토큰이 갱신되어 서버와 동기화가 필요한 경우
- 프론트에서 onTokenRefresh() 메소드를 오버라이딩하여, 로그인된 유저의 토큰이 갱신될 경우 서버로 토큰을 업데이트하는 API를 전송
4. 오래된 토큰이 있는 비활성 장치에 메시지를 전송하면 리소스를 낭비할 수 있음
푸시 메시지 전송 시 FCM 토큰의 값이 유효하지 않다면 아래와 같은 에러코드가 리턴된다.
- UNREGISTERED(HTTP 404)
- INVALID_ARGUMENT(HTTP 400)
Firebase Docs에 따르면 토큰 타임스탬프의 2개월이 지난 토큰은 비활성화된, 유효하지 않는 토큰으로 간주한다.
따라서, 2개월마다 토큰 유효성 검사 후 토큰 업데이트를 해주는 것을 추천한다고 한다.
send()를 통해 하나하나의 token에 메시지를 보내고 체크하기엔 효율성이 좋지않다.
이 때문에 Topic을 이용해 구독 후 에러가 발생하는 token을 뽑아내려고 했으나,
test Topice을 남겨놓는 것도 좋지 않을 것 같아 구독 후 다시 unsubscribe를 해줘야하기 때문에 포기했다.
예제 1. token 각각 메시지 보내기
public boolean checkToken(String fcmToken){
try{
Message message = Message.builder()
.setToken(fcmToken)
.build();
FirebaseMessaging.getInstance().send(message);
return true;
}catch (FirebaseMessagingException e){
return false;
}
}
예제 2. Topic 구독 방식
public void checkToken(){
List<String> tokenList = deviceRepository.findAllBy().stream().map(
device -> device.getToken()
).collect(Collectors.toList());
// 구독
FirebaseMessaging.getInstance().subscribeToTopic(tokenList, "fcm-test");
// 구독취소
FirebaseMessaging.getInstance().unsubscribeFromTopic(tokenList, "fcm-test");
}
만약 device 전체 정보를 가져오는 것이 무겁다면, Interface를 생성해 아래처럼 원하는 정보만 가져올 수 있다.
** Interface
public interface DeviceFCMToken { String getToken(); }
** Repository
List<DeviceFCMToken> findAllBy();
위에 방법 말고 검색해보니 일괄 메시지 전송이 적합할 것 같았다.
일괄 메시지 전송에는 두가지 방법이 있다.
기존 각각의 토큰을 이용해 메시지를 보내는 방법과 같은 sendAll 방식(Message)과
MulticastMessage를 이용하는 sendMulticast 방식이 있다.
예제1. sendAll
최대 500개의 메시지를 전송할 수 있다고 한다.
sendAll도 BatchResponse를 이용해 결과값을 받을 수 있지만, 메시지를 하나하나 세팅해야해서 이번 취지와는 맞지 않다.
// Create a list containing up to 500 messages.
List<Message> messages = Arrays.asList(
Message.builder()
.setNotification(Notification.builder()
.setTitle("Price drop")
.setBody("5% off all electronics")
.build())
.setToken(registrationToken)
.build(),
// ...
Message.builder()
.setNotification(Notification.builder()
.setTitle("Price drop")
.setBody("2% off all books")
.build())
.setTopic("readers-club")
.build()
);
BatchResponse response = FirebaseMessaging.getInstance().sendAll(messages);
// See the BatchResponse reference documentation
// for the contents of response.
System.out.println(response.getSuccessCount() + " messages were sent successfully");
예제2. sendMulticast
sendMulticast는 sendAll과 다르게 메시지를 하나하나 세팅하는 것이 아닌,
토큰을 리스트형식으로 받아 전송한다.
response 값을 받아 오류가 발생한 내역도 확인이 가능하다.
public BatchResponse sendMessage(List<String> targetToken) throws FirebaseMessagingException {
MulticastMessage message = MulticastMessage.builder()
.addAllTokens(targetToken)
.build();
BatchResponse response = FirebaseMessaging.getInstance().sendMulticast(message);
List<SendResponse> responses = response.getResponses();
for (int i = 0; i < responses.size(); i++) {
if (!responses.get(i).isSuccessful()) {
deviceList.get(i).setTokenStatus(TokenStatus.Disabled);
}
}
}
참고사이트
'💡 백엔드 > FCM ( Firebase )' 카테고리의 다른 글
[FCM] Java에서 Firebase 실시간 데이터베이스 활용하기 (0) | 2023.07.07 |
---|---|
[FCM] 푸시 메시지를 보내는 방법 2가지 (0) | 2023.07.06 |
[FCM] FCM 웹 푸시 메시지 보내기 (0) | 2023.07.04 |
[FCM] FCM이란? (0) | 2023.06.15 |