오늘 배운 것

오늘은 우선 구글 플레이스토어 콘솔에서 배포가 잘 되고 있는지 확인했다. 다행히 아직까지는 오류가 난 것이 없어서, 당장 세 명이 뛰어들 만한 급한 이슈는 없다고 판단했다. 

 

어제 잘 돌아가는 것을 확인한 서버를 일단 켜 두자. 프론트엔드와 백엔드 서버 모두 켜 두었다. 

 

일단 디자인은 잠시 미뤄둔 상황이다. 그리고 구글 플레이스토어의 앱 배포도 아직까지는 문제가 없다. 물론 다운로드 수가 20을 넘어야 하지만, 그건 차차 사용자 수를 모으면 되는 상황이므로 현재의 문제는 아니다. 그렇다면 이 상황에서 뭘 우선으로 해야 할까? 일단 앱이 배포된 다음에는, 사용자를 모으는 것이 우선이다. 사용자를 모으려면 우선은 앱이 정상 작동을 해야 하고, 고도화 기능(알람과 하위투두 고도화)이 필요하며, 틈틈이 홍보도 해야한다. 

 

논의 끝에 팀원 한 명은 앱의 정상 작동을 위해 버그를 고치는 일, 다른 한 명은 하위 투두 고도화를 위해 DB 및 모델을 설계하는 일, 그리고 나는 알람을 맡았다. 계속 미뤄지게 된 알람 이슈를 작업하게 된 것이다. 

 

사실 이미 작성된 로직이 있었어서, 해당 로직이 잘 작동하는지 확인을 하면 되었다. 문제는 결과값 자체는 잘 보내진다고 나오는데 에뮬레이터 기기에 알림이 오지 않는다는 점이었다. 

 

원인을 추측해 보자면 해당 토큰값이 에뮬레이터의 FCM 토큰값이 아니거나, 코드에 있는 Messaging 또는 Notification 객체가 제대로 동작하지 않았을 수 있겠다. 

 

우선 첫 번째 추측의 경우, 프론트에서는 다음과 같은 코드로 기기의 FCM 토큰을 가져오고 있었다. 이는 RN 공식문서에도 나와있는 방법이므로 이게 틀릴 가능성이 꽤 낮았다. (사실 만약 틀렸다고 하면, 깃헙 이슈를 보면서 어떻게 해야 하는지를 또 일일이 찾아봐야 해서 그게 아니길 바란다.)

import messaging from '@react-native-firebase/messaging';
const token = await messaging().getToken();

 

... 라고 생각했었는데, 알고보니 프론트에서 다른 브랜치로 작업을 하고 있었다. 즉 백엔드에서 맞는 기기로 알림을 보내도 프론트엔드에서 그 메시지를 받아서 표시해주는 로직이 동작해야 화면에 알림이 표시되는데, 그 로직을 작성해놓은 브랜치가 아니었던 것이다. git checkout과 git rebase(앱이 동작하지 않는 문제가 dev 브랜치에서 고쳐진 상태였기 때문에 rebase도 같이 했다)을 하고 다시 시도해 보았다. 여전히 되지 않았다. 

 

백엔드에서는 로직 중간에 오류가 없는 것으로 보아 프론트엔드의 알림을 받는 부분에 문제가 있을 것이라고 추측했다. 짚이는 부분 하나는 프론트에 현재 알림이 오면 그걸 그대로 화면에 나타내주는 코드가 없다는 거였다. 또한 헷갈렸던 부분은, 메시지를 보내거나 받을 때 디바이스의 FCM 토큰만 알면 별도로 채널 등의 정보를 따로 지정하지 않아도 무사히 해당 FCM 토큰을 가진 디바이스에서 메시지를 받을 수 있는지 의문이 들었다. 

 

다시 RN firebase 공식문서fcm django 공식문서를 보자. 공식문서를 보면서 여러 문제점을 찾았다. 첫 번째는 fcm-django에서 메시지를 보내려면 fcm-django에서 정의한 FCMDevice라는 모델을 사용해야 한다. 정확히는 해당 모델의 send_message 라는 메소드를 통해서 메시지가 보내진다. 그런데 그 부분이 코드에서 빠져 있었다. 아마도 디바이스 토큰 값은 정확했을 텐데 메시지가 제대로 전송되지 않은 것 같았다. 

 

그러면 이전에 임의로 정의해두었던 Device 모델 대신에 FCMDevice 모델을 사용해야 한다. 이를 위해서 해당 코드가 있는 구글로그인 로직의 일부를 바꿔주었다.

 

기존의 Device 모델에서 get_or_create 메소드를 통해 device_token(앞서 프론트에서 보내는 device token 값)의 값을 가진 Device 인스턴스가 있으면 이를 불러오고 없으면 만들어 주었다. 이번에도 마찬가지로 FCMDevice에서 get_or_create 메소드를 사용하려고 했는데, 그러려면 device_token 값을 어떤 필드에 저장해야 할지를 알아야 했다. 

 

fcm_django.models에 관련 모델들이 모두 정의되어 있었다. 우리가 사용하려는 FCMDevice는 AbstractFCMDevice를, AbstractFCMDevice 모델은 Device 모델을 상속받고 있었다. 그래서 이 FCM 토큰 값을 어디다 넣으라는 건가 싶었는데, 공식문서에 친절히 registration_id 필드에 넣으라고 나와있었다.

 

기존의 Device 모델에서 FCMDevice 모델로, 그리고 일부 필드값만 바꿔주었다. 

FCMDevice.objects.get_or_create(
    user=user, registration_id=device_token
)

 

그리고 'python manage.py showmigrations' 명령어로 확인해 보니 fcm_django 라이브러리와 관련된 모델 변경 사항이 아직 마이그레이션에 반영되지 않은 상태였다. 이것도 반영해 주었다. 

 

이렇게 기본 로직을 변경하고, 다시 프론트 에뮬레이터를 켜서 구글로그인을 한 번 실행해 주었다. 그래야 FCMDevice 모델에 해당 에뮬레이터의 토큰 값이 들어가기 때문이다. 그리고 나서 기존의 메시지를 보내는 로직을 다시 바꿔주었다. 

def send_push_notification(token, title, body):
    message = messaging.Message(
        notification=messaging.Notification(
            title=title,
            body=body,
        ),
    )
    device = FCMDevice.objects.filter(registration_id=token).first()
    try:
        device.send_message(message)
    except Exception as e:
        # sentry capture exception
        return PUSH_NOTIFICATION_ERROR
    return PUSH_NOTIFICATION_SUCCESS

 

이렇게 바꿔 주었고 메시지를 보내는 로직을 실행시키니 success라고 떴다. 그런데 여전히 에뮬레이터에서는 알림이 표시되지 않아서, 이번에는 프론트 쪽에 문제가 있을 가능성을 두고 프론트 코드를 고쳐봐야 할 것 같다. 

 

 궁금한 점

1. kafka-python 등의 kafka를 python에서 사용하기 위한 라이브러리가 있는 걸로 알고 있다. 문득 우리 서비스에서 kafka-python과 같은 라이브러리가 필요할 일이 있을지 궁금해졌다. 

2. FCMDevice의 send_message 로직은 어떻게 되어 있을까?

 

 오늘의 러닝 인증

 

+ Recent posts