앱 서비스에서 푸시알림(push notification)은 필수 조건이다.
이 중 가장 레퍼런스도 많고 자료도 많은 FCM을 사용해봤는데, 설정도 편하고 굳이 APNs 서버 만들 필요도 없어서 너무 간편했다.
푸시알림을 보내기 위해선 fcm에서 SDK, http v1 api 이 두 가지 방식을 지원하는데,
나는 그냥... 편하게 sdk를 사용하였다.
이건 좀 tmi인데, 다중 전송은 SDK로 보내게되면 묶어서가 아니라 메세지 한 개씩만 쏴서 매우 비효율적이라고 한다.
따라서 나중에 광고성 알림같은 broadcast로 보낼 땐 http v1으로 보내지 않을까 싶다.
아무튼, 기초적인 틀은 다음과 같다.
from firebase_admin import messaging
from firebase_admin.exceptions import FirebaseError
def sent_to_fcm(token, title, body, deep_link):
# 메세지 설정
message = messaging.Message(
notification=messaging.Notification(
title=title,
body=body
),
token=token,
data={"url": deep_link}
)
# 메세지 보내기
try:
response = messaging.send(message)
return response
# 실패하면 에러 코드 및 메세지 반환
except FirebaseError as e:
return {"error_code": e.code, "message": e}
우리가 흔히 보는 구성으로 생각한다면, [ title / body / token / deep_link ]가 필요하다.
title: 푸시 알림의 제목. 보통 앱 이름이 들어간다. (굵은 색 글씨)
body: 푸시 알림의 내용.
token: 어느 사용자에게 보낼 것인지에 대한 식별자
deep_link: 이 메세지를 확인했을 때 어느 링크로 가는지
이것 외에도 사진이나 우선순위(해당 내용 구글링 추천 ㅎ) 등등... 넣을 수 있다.
또한, 이대로만 하면 안드로이드에선 푸시알림이 오지 않는데, 메세지 설정 시 channel_id를 추가적으로 설정해줘야 한다.
android=messaging.AndroidConfig(
notification=messaging.AndroidNotification(
priority="high",
click_action="NOTIFICATION_CLICK",
channel_id="channel_id"
)
)
(사실 FCM에만 해당되는 내용이 아닐 수 있다ㅎ)
이모지(emoji)가 포함된 메세지를 python으로 다루고 FCM으로 보내는 건 어렵지 않지만 귀찮은 일이었다.
만약 🤗 이모지를 보내고 싶다면, 사용자 기기에서 읽을 수 있도록 UTF-16로 전송해야 한다.
따라서 해당 이모지를 복사하여, UTF-16로 변환해주는 아래 사이트를 이용해야 한다.
https://onlinetools.com/unicode/convert-unicode-to-utf16
Input Unicode에 이모지를 붙여놓으면 오른쪽 'Output UTF-16'에 두 단어가 보이는데,
이 두 단어 앞에 \u를 붙인 다음에 띄어쓰기없이 나열하면 된다.
message = "\ud83e\udd17"
내 경우엔 메세지를 DB에 저장하면서 FCM으로 사용자에게 보내는 로직이었는데...
UnicodeEncodeError: 'utf-8' codec can't encode characters in position 0-1: surrogates not allowed
이런 오류가 발생하였다ㅎ.
일단 surrogate가 무엇인지 알 필요가 있다.
Surrogate는 UTF-16에서 BMP를 벗어나는 문자를 표현하기 위해 사용된다.
BMP는 다국어를 지원하기 위해 체계적으로 \U0000부터 \UFFFF까지의 영역을 차지하고 있다. 자세히 알고싶다면 이 링크로^^
하지만 이모지는 다국어가 아니기 때문에 하나의 코드로 제공할 수 없기에, 두 개가 한 쌍으로 이루어 표기된다. 따라서 \UD83E와 \UDD17 이 두 개가 하나의 이모지 🤗로 표현된다.
이 때, 파이썬은 이 surrogate를 제대로 처리하지 못하지만 처리해보겠다고 아둥바둥하다 오류를 낸 것이다.
구글링 끝에 해당 에러는 다음 코드와 같이 처리하였다.
.encode('utf-16_BE','surrogatepass').decode('utf-16_BE')
생각보다 쉬웠는데, encode와 decode할 때는 utf-16으로 동일하게 하지만 encode할 때는 surrogate pass 옵션을 줬다.
Surrogate pass는 말 그대로 surrogate 처리하지 않겠다는 의미와 같은데,
만약 \UD83E\UDD17가 한 쌍으로 붙어있으면 surrogate라고 생각하지 않고 개별의 코드 두 개인 \UD83E와 \UDD17로 생각하여 인코딩하고 byte형태로 반환한다는 뜻이다.
그리고 이걸 바로 우리가 읽을 수 있는 문자열 형태로 decode 해야하는데,
내가 원했던대로 \UD83E\UDD17로 된다! (이모지 db, 사용자 기기에게 맡기는 걸로)