작성 내용
1편에서 FCM에 대한 기초 개념과 그 구조, 메시지의 종류에 대해 알아봤다. 이 때, 메시지의 종류에 따라 전달하는 것이 다르다는 것을 확인 할 수 있었다.
이는 메시지 종류에 따라 달라지는 것으로, 이번에는 메시지 종류가 아닌 전달하는 플랫폼에 따라 달라지는 것을 확인하고자 한다.
이번 게시글은 FCM의 전반적인 부분을 다루기 때문에 안드로이드가 중심이라 보기에는 어렵지만, 원활한 개발을 위해선 알아두어서 좋을 것이라 판단하였기 때문에 공식문서에 있는 것은 제대로 정리하고자 한다.
플랫폼간 Message Customizing
Firebase Admin SDK
및 FCM v1 HTTP Protocol
사용시, 메시지 Request에서 메시지 객체에서 사용 가능한 모든 필드를 설정할 수 있다. 이 필드엔 다음 2개가 포함된다.
1. 메시지를 수신하는 모든 앱 Instance
에서 해석할 공통 필드 집합
2. 지정된 플랫폼에서 실행되는 앱 Instance
에서만 해석되는 AndroidConfig
및 WebpushConfig
와 같은 플랫폼별 필드 집합(platform-specific set of fields)
→ 플랫폼 별 블록은 수신 시 플랫폼 각각에 맞게 올바르게 처리되도록, 다양한 플랫폼에 대한 메시지를 커스텀할 수 있는 Flexibility을 제공한다. FCM Backend
는 specified된 모든 매개변수를 고려해, 각 플랫폼에 대한 메시지를 커스텀한다.
Common Fields
사용하는 상황
- 모든 플랫폼에 대한 app instances targeting
- Sending Messages to topics
플랫폼과 관계없이 해석 가능한 공통필드
1. message.notification.titile
2. message.notification.body
3. message.data
Platform-Specific set of Fields
사용하는 상황
- 특정 플랫폼에만 필드를 보내는 경우
- 공통 필드 이외에 추가적인 플랫폼 별 필드를 보내는 경우
주의점
- 특정 플랫폼에만 값을 보내길 원하는 경우엔,
Common Fields
를 사용해선 안되며,platfom-specific fields
로 사용해야 한다. - 예를 들어, 안드로이드를 제외한
Apple
과web
플랫폼에만 보내고자 하는 경우, 각각 2개의 분리된sets of fields
를 사용해야 한다. - 특정
delivery options
으로 메시지를 보내는 경우,platform-specific fields
를 사용해 설정한다. 원하는 경우, 플랫폼 별로 다른 값을 지정할 수 있다. 그러나, 플랫폼 간에 기본적으로 동일한 값을 설정하는 경우에도platfom-specific fields
를 사용해야 하는데, 플랫폼마다 다르게 해석할 여지가 있기 때문이다.- 예를 들어, TTL(Time-To-Live)는 안드로이드에서는 만료 시간이 (초)단위로 설정되는 반면,
Apple에서는 만료 일자 단위로 설정되기 때문이다.
- 예를 들어, TTL(Time-To-Live)는 안드로이드에서는 만료 시간이 (초)단위로 설정되는 반면,
Platform-specific delivery options이 있는 Notification Message
아래의 예시는 모든 플랫폼에 대해 공통 notification title
과 content
를 전송하지만, 일부 platform-specific overrids도 전송한다.
안드로이드와
Web
플랫폼에 대해TTL
를 긴 시간으로 설정하고,APNs
메시지priority
를 low setting으로 setting안드로이드와
Apple
의 알림에 대한 사용자 탭의 결과를 정의하는 적절한 키(click_action
, 와category
)를 설정
메시지 본문의 platform-speicific block에서 사용할 수 있는 key에 대한 자세한 내용은 HTTP v1 참조 문서
를 참고. 메시지 본문을 포함하는 보내기 request building에 대한 자세한 내용은 보내기 요청 작성을 참고
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Match update",
"body":"Arsenal goal in added time, score is now 3-0"
},
"android":{
"ttl":"86400s",
"notification"{
"click_action":"OPEN_ACTIVITY_1"
}
},
"apns": {
"headers": {
"apns-priority": "5",
},
"payload": {
"aps": {
"category": "NEW_MESSAGE_CATEGORY"
}
}
},
"webpush":{
"headers":{
"TTL":"86400"
}
}
}
}
Delivery Options
FCM은 안드로이드 기기로 전송되는 메시지에 대한 specific set of delivery option
을 제공하며, Apple
과 웹
플랫폼에서 유사한 option을 허용한다.
예를 들어, collapsible message
동작을 조절하고자 한다
1. Android
경우엔 FCM의 collapse_key
를 통해
2. Apple
은 apns-collapse-id
를 통해
3. JavaScript/Web
은 Topic
을 통해 가능하다.
1. Non-Collapsible과 collapsible message
Non-collapsible
Non-collapsible
메시지는 각각의 개별 메시지가 기기로 전송됨을 의미한다. 해당 메시지는 data
를 fetch
하기 위해 서버에 접근하는 모바일 앱에 ping
처럼 content-free
과 같은 collapsible
메시지와 달리, 유용한 content
를 전달한다.
FCM은 전달 순서를 보장하지 않는다.
Non-collapsible의 예시
채팅이나 중요한 메시지가 이에 해당된다.
안드로이드의 경우, collapsing
없이 저장할 수 있는 메시지는 100개로 제한된다.
제한 도달시, 저장된 모든 메시지가 삭제된다. 장치가 다시 온라인 상태가 되면, 제한에 도달했음을 나타내는 특수 메시지가 수신된다.
그러한 다음, 일반적으로 앱 서버에서 전체 동기화를 요청해 적절히 처리할 수 있다.
collapsiable
collapsible
메시지는 기기에 아직 도달되지 않은 경우, 새 메시지로 대체될 수 있는 메시지이다.
collapsible의 예시
일반적으로, 서버에서 데이터를 동기화하도록 모바일 앱에 알리는데 사용되는 메시지로, 예를 들어 가장 최신 점수로 유저를 업데이트 하는 스포츠 앱에서는 최근 메시지만 관련있기 때문에 이전 메시지를 덮어씌운다고 생각하면 된다.
안드로이드에서 메시지를 collapsible
로 표시하려면 메시지 payload
에 collapse_key
매개변수를 포함시킨다. 기본적으로, collapse key
는 Firebase 콘솔에 등록된 앱 패키지 이름이다.
FCM 서버는 각각 다른 collapsible key
를 사용해, 기기당 4개의 서로 다른 collapsible 메시지
를 동시에 저장할 수 있다. 이를 초과하면 FCM은 collapse key
를 4개만 유지하며, 어떤 키가 유지되는지는 보장하지 않는다.
또한, payload가 없는 Topic message는 기본적으로 collapsible이다.
Notification Message
는 항상 collapsible
이며, collapsible_key
매개변수를 무시한다.
사용 상황
일반적으로, non-collapsible
를 사용할 필요가 없는 경우엔 collapsible
이 성능적으로 더 나은 선택이다.
그러나, collapsible
을 사용하는 경우에는 FCM는 registration token
당 항상 최대 4개의 다른 collapse key
를 사용할 수 있다는 것을 명심해야 하며, 이를 초과해선 안된다.
2. Message 우선순위 설정
Priority 종류
Downstream 메시지에 delivery 우선순위를 할당하는데는 normal
과 high
priority가 존재한다.
작성 방법
동작은 플랫폼마다 살짝 다르지만, normal
및 high
우선순위 메시지 전달은 다음과 같이 작동한다.
Normal priority
: 일반 우선순위 메시지는 앱이Foreground
에 있는 경우 즉시 전달된다.Background
에 있는 경우엔 전송이 지연될 수 있다. 새 이메일 알림, UI 동기화 유지또는Background
에서의 앱 데이터 동기화와 같이 시간에 덜 민감한 메시지의 경우 선택하면 된다.High Priority
: FCM은 기기가Doze mode
(잠자기 모드)인 경우에도 즉시 전달하기 위해 시도한다. 해당 우선순위는, time-sensitive한 유저가 볼 수 있는 content이다.- 애플 기기에 메시지를 보내는 경우엔 우선순위를
5
또는,normal
로 설정해야 한다.high
priority의 메시지는INVALID_ARGUMENT
에러와 함께 FCM Backend에서 거부된다.
작성 예시
{
"message":{
"topic":"subscriber-updates",
"notification":{
"body" : "This week's edition is now available.",
"title" : "NewsMagazine.com",
},
"data" : {
"volume" : "3.21.15",
"contents" : "http://www.news-magazine.com/world-week/21659772"
},
"android":{
"priority":"normal"
},
"apns":{
"headers":{
"apns-priority":"5"
}
},
"webpush": {
"headers": {
"Urgency": "high"
}
}
}
}
3. Message Lifespan(수명) 설정
FCM은 일반적으로 메시지 전송 직후 deliver하지만, 항상 가능한 것은 아니다.
예를 들어, 안드로이드 플랫폼의 경우 기기가 꺼져있거나 오프라인등에서는 사용할 수 없다. 혹은, FCM은 앱의 과도한 리소스를 소비하고, 배터리 수명에 부정적 영향을 미치지 않도록 의도적으로 메시지를 지연시킬 수 있다.
따라서 이 경우에는 메시지를 곧바로 전달할 수 없기 때문에, FCM은 메시지를 저장하고, 가능한 빨리 전달한다.
이러한 행동은 대부분은 괜찮지만, 이렇게 메시지 전달이 늦어질 경우 전달 자체를 하지 않는 경우도 있다.
전달되지 않는 예시
- Video chat incoming calls
- Expiring invitation events
- Calendar events
전달되지 않는 이유
메시지가 전달되는 짧은 시간동안만 의미가 있기 때문이다.
이러한 앱은 메시지가 수신 전화/화상 채팅 알림이거나 이벤트에 대한 초대인 경우엔인 경우엔 종료되기전 짧은 시간동안만 의미가 있기 때문이다.
그렇기 때문에 Android
와 Web/Javascript
에선 메시지의 최대수명 지정이 가능한데, 값은 0에서 2,419,200초(28일)사이의 기간이며, FCM이 메시지를 저장하고 전달을 시도하는 최대 기간에 해당된다.
이 필드에 포함하지 않는 요청은 최대인 4주로 기본 설정된다.
Lifespan 설정의 이점
메시지의 수명을 지정하는 다른 장점은 FCM이 TTL값이 0초인 메시지를 제한하지 않는다는 것이다.
즉, FCM은 “Now or Never
” 전달해야 하는 메시지에 대해 최선의 노력을 보장한다는 것이다.
time-to-live
값이 0이면, 즉시 전달할 수 없는 메시지는 discard되지만,
저장되지 않기 때문에 이것은 notification message
전송을 위한 best latency
를 제공하게 되는 것이다.
설정 예시
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
},
"apns":{
"headers":{
"apns-expiration":"1604750400"
}
},
"android":{
"ttl":"4500s"
},
"webpush":{
"headers":{
"TTL":"4500"
}
}
}
}
Message의 LifeTime (수명)
앱 서버가 FCM에 메시지를 post하고, 메시지 ID를 다시 receives했다고 해서, 이것이 기기에 이미 전달되었다는 의미는 아니다.
오히려 delivery를 위해 이것이 accepted되었다는 의미가 맞다. 메시지가 수락된 후 발생하는 작업은 여러 요인에 따라 달라진다.
기기 연결상황별 전달 방법
1. 기기가 FCM에 연결되어 있고, 화면이 켜져있으며, 쓰로틀링 제한이 없는경우
가장 좋은 시나리오로 메시지가 바로 전달된다
2. 기기가 FCM에 연결되어 있지만, Doze(잠자기) 모드인 경우
기기가 잠자기 상태에서 벗어날 때까지 우선순위가 낮은 메시지가 FCM에 의해 저장된다. 이곳이 바로 collapse_key
flag가 역할을 하는 곳인데, 동일한 collapse key
가 저장되어 있고, 전달을 기다리는 메시지가 있는 경우 이전 메시지는 삭제되고, 새 메시지가 그 자리를 차지하기 때문이다. 그러나, collapse key
가 설정되어 있지않으면, 향후 전달을 위해 새 메시지와 이전 메시지 모두 저장된다.
3. 기기가 FCM에 연결되어 있지 않은 경우
(1) 연결이 설정될 때까지, 메시지가 저장되고,
(2) 연결이 설정되면 FCM은 보류중인 모든 메시지를 장치로 전달한다.
기기가 다시 연결되지 않으면, 메시지는 시간초과되어 FCM 저장소에서 삭제되며, Time-to-live flag가 설정되지 않은 경우 기본 제한 시간은 4주이다.
direct channel messaging
이 활성화된 안드로이드
기기에 대해서는, FCM에 한달 이상 연결되지 않은 경우엔 FCM은 여전히 메시지를 수락하지만, 즉시 discrads된다.
마지막 데이터 메시지를 보낸 후 4주 이내에 장치가 연결되면 클라이언트는 onDeletedMessages()
callback을 받는데,
이를 이용해 앱 서버에 전체 동기화를 요청해서 그동안 있었던 상황을 적절히 처리할 수 있다.
4. FCM이 기기에 메시지 전달을 시도하고, 앱이 제거된 경우
FCM은 해당 메시지를 즉시 삭제하고, Registration Token
을 즉시 삭제한다.
나중에 해당 기기로 메시지를 보내려고 시도하면, NotRegisterd
오류가 발생한다.
Throttling과 Scaling
FCM을 통해 항상 전송된 모든 메시지를 deliver하려 하지만, 모든 메시지 전달시에 UX가 저하되는 결과를 초래하는 경우가 있다.
따라서 boundaries
를 제공해야 한다
Collapsible Message Throttling
collapsible
메시지는 서로 위에 접힐수 있도록 디자인된 content-free notifications
이다. 개발자가 앱에 동일한 메시지를 너무 자주 반복하는 경우, 사용자의 배터리에 미치는 영향을 줄이기 위해, 메시지를 지연(조절)한다.
예를 들어, 단일 기기에 많은 수의 새 이메일 동기화 요청을 보내는 경우, 기기가 더 낮은 평균 속도로 동기화할 수 있도록, 이메일 동기화 요청을 지연시킬 수 있고, 이 throttling
은 엄격하게 사용자가 경험하는 배터리 영향을 제한하기 위해 수행된다.
high burst send patterns
이 필요한 경우에는 non-collapsible
메시지가 맞는 방향일 수 있다. 이러한 메시지의 경우에는 배터리 비용을 줄이기 위해, 해당 메시지에 내용을 포함해야 한다.
접을 수 있는 메시지는 기기별 앱당 20개의 메시지로 제한되며, 3분마다 1개의 메시지가 채워진다.
XMPP Server Throttling
단일 기기에 대한 최대 메시지 Rate
안드로이드의
경우 단일 기기
에 분당 최대 240개의 메시지 및 시간당 최대 5,000 메시지를 보낼 수 있다.
해당 임계값은 사용자가 채팅을 통해 빠르게 상호작용하는 경우와 같이 단기간의 트래픽 급증을 허용하기 위함이며,
이 제한은 로직 전송 오류로 장치의 배터리가 실수로 소모되는 것을 방지한다.
iOS
의 경우에는 속도가 APN 제한을 초과하면 오류가 반환된다.
→ 이 최대 속도 근처에서 정기적으로 메시지를 보내는 경우, 유저의 리소스가 낭비될 수 있고 어뷰징 앱으로 마킹될 수 있으므로 권하지 않는다고한다.
Upstream Message 제한
upstream
destination 서버에 대한 과부하 방지를 위해, upstream
메시지를 프로젝트당
분당 1,500,000개로 제한한다.
잘못된 앱 동작으로 인한 배터리 소모 방지를 위해 기기당
upstream 메시지를 분당 1,000개로 제한한다.
Topic Message 제한
Topic subscription add/remove rate는 프로젝트당 3,000 QPS로 제한하며, 메시지 전송속도는 Fanout Throttling 을 참고한다.
'IT > Android' 카테고리의 다른 글
[Android/FCM] (4) Android 설정 (0) | 2023.03.07 |
---|---|
[Android/FCM] (3) Registration Token 관리 (0) | 2023.03.02 |
[Android/FCM] (1) Firebase Cloud Messaging의 기초 개념및 구조 (0) | 2023.02.05 |
[Android/Retrofit] Effective Error Handling을 위한 CallAdapter의 활용 (0) | 2023.01.25 |
[Android Dev] RecyclerView의 스크롤 상태 체크 (0) | 2023.01.22 |