nestjs에서 fcm 알림 전송하기

Uhan33·2024년 4월 25일
0

TIL

목록 보기
71/72

저번에 클라이언트에서 FCM 토큰을 받아오는 방법을 작성하였는데,
이번에는 백엔드 서버에서 fcm 알림을 전송하는 방법을 작성해보려 한다.
추가로, 내가 구현해야했던 일정 시간에 알림 전송하기까지 정리해보겠다.

우선 firebase-admin 라이브러리를 설치하자.

npm i firebase-admin

그리고 firebase console에 가면, 만들어둔 프로젝트의 프로젝트 설정에서 서비스계정이라는 메뉴가 있다.
여기서 새 비공개 키 생성 버튼을 누르고 키 생성을 해서 다운로드 받으면 JSON 파일이 받아진다.

이를 프로젝트 폴더에 넣어주어 사용하거나, env파일에 잘 정리해서 넣어주자.
이번 글에서는 단순하게 폴더 안에 넣어 사용해주려 한다.

const firebase_params = {
  type: firebaseConfig.type,
  projectId: firebaseConfig.project_id,
  privateKeyId: firebaseConfig.private_key_id,
  privateKey: firebaseConfig.private_key,
  clientEmail: firebaseConfig.client_email,
  clientId: firebaseConfig.client_id,
  authUri: firebaseConfig.auth_uri,
  tokenUri: firebaseConfig.token_uri,
  authProviderX509CertUrl: firebaseConfig.auth_provider_x509_cert_url,
  clientC509CertUrl: firebaseConfig.client_x509_cert_url,
};

@Injectable()
export class MessageService {
  constructor() {
    admin.initializeApp({
      credential: admin.credential.cert(firebase_params),
    });
  }

이제 FCM 전송을 위한 준비는 끝났고, 코드를 짜보자
일단 방식은 payload에 보내고자 하는 클라이언트의 fcm 토큰과 알림 메세지 내용을 넣어준다.
그리고, admin.messaging().send()를 통해 메세지를 전송해주는 방식이다.
코드를 보겠다.

  async sendFcm(token: string, title: string, message: string) {
    const payload = {
      token: token,
      notification: {
        title: title,
        body: message,
      },
      data: {
        body: message,
      },
    };
    console.log(payload);
    const result = await admin
      .messaging()
      .send(payload)
      .then((response) => {
        return { sent_message: response };
      })
      .catch((error) => {
        return { error: error.code };
      });

    return result;
  }

result에는 성공하면 본인의 project_id와 발송한 message의 id가 들어있다.

본인은 이 메세지 알림 기능을 활용해서 유저가 스케줄을 등록하면 등록한 날짜와 시간이 되기 10분 전에 유저의 브라우저에 알림 메세지를 띄우고자 했다.
그래서 nestjs의 scheduler를 사용하기로 했고, 그 중 Cron을 사용했다.
근데 데코레이터로 Cron을 사용하기엔 동적으로 Cron의 값을 바꿔줄 수가 없어서
CronJob을 사용해 동적 스케줄링을 구현해주었다.
코드를 봐보자. 우선 Date가 들어오면 해당 시간에 맞춰서 알림을 보내주는 코드이다.

  constructor(
    private schedulerRegistry: SchedulerRegistry,
  ) {
    admin.initializeApp({
      credential: admin.credential.cert(firebase_params),
    });
  }

  async addCronJob(token:string, title:string, message:string, ptTime:Date, id:string) {
    const job = new CronJob(new Date(`${ptTime}`), async () => {
      const payload = {
        token: token,
        notification: {
          title: title,
          body: message,
        },
        data: {
          body: message,
        },
      };
      console.log(payload);
      const result = await admin
        .messaging()
        .send(payload)
        .then((response) => {
          return { sent_message: response };
        })
        .catch((error) => {
          return { error: error.code };
        });
    })

    this.schedulerRegistry.addCronJob(id, job);
    job.start();
  }

사실상 이전에 사용한 sendFcm 함수와 다른점이라고는 CronJob으로 덮여있고 이를 실행해주기 위해 마지막 두 줄의 코드가 추가된 정도이다.

ptTime에 따라 CronJob이 실행되는 시간이 다르고,
id 또한 중복되면 안되기에 uuid를 사용하였다.
원래는 response에 있는 messageID를 사용하려 했으나
어떤 이유인지 해당 값이 불러와지지 않아 uuid를 사용하는 것으로 결정했다.

스케줄을 생성하면 동시에 알림이 전송되고,

지정해준 시간의 10분 전에 알림이 다시 오게된다.

0개의 댓글