๐Ÿ“Œ Firebase๋ฅผ ์ด์šฉํ•œ ํ‘ธ์‹œ์•Œ๋ฆผ flow

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” firebase๋ฅผ ์œ ์šฉํ•˜๊ฒŒ ์“ฐ๊ณ  ์žˆ๋Š”๋ฐ, ํ‘ธ์‹œ ์•Œ๋ฆผ๋„ ํŒŒ์ด์–ด ๋ฒ ์ด์Šค์—์„œ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์žˆ์–ด์„œ ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค!

์ถœ์ฒ˜: https://noonestaysthesame.tistory.com/m/17

๋ฐฑ์—”๋“œ๋Š” fcm ์„œ๋ฒ„์— ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ์ „์†กํ•˜๊ณ  ํ”„๋ก ํŠธ์—”๋“œ๋Š” fcm ์„œ๋ฒ„์— ์žˆ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ํ•ด๋‹น ๋””๋ฐ”์ด์Šค์— ์•Œ๋ฆผ์„ ๋„์›Œ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

 

 ๐Ÿ“Œ Firebase๋กœ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ ์ค€๋น„ ๊ณผ์ •


1, Firebase project ์ƒ์„ฑ ํ›„, ํ„ฐ๋ฏธ๋„์—์„œ Firebase Admin SDK ์„ค์น˜

$ npm install firebase-admin --save


2. SDK ์ดˆ๊ธฐํ™”๋ฅผ ์œ„ํ•œ ์„œ๋ฒ„ ํ‚ค ๋‹ค์šด๋กœ๋“œ
ํ”„๋กœ์ ํŠธ ์ฝ˜์†”๋กœ ์ด๋™ -> ์„œ๋น„์Šค ๊ณ„์ • -> ํ‚ค ์ƒ์„ฑ

ํ•˜๋‹จ์˜ ์ƒˆ ๋น„๊ณต๊ฐœ ํ‚ค ์ƒ์„ฑ ํด๋ฆญ!


3. SDK ์ดˆ๊ธฐํ™” ์ฝ”๋“œ ์ž‘์„ฑ
์œ„์˜ ์‚ฌ์ง„์— ๋ณด์ด๋Š” ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•ด์„œ ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•œ๋‹ค.

var admin = require("firebase-admin");

var serviceAccount = require("path/to/serviceAccountKey.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

์ค‘๊ฐ„์— "path/to/serviceAccountKey.json"์€ ํ•ด๋‹น ํ‚ค ๊ฒฝ๋กœ๋ฅผ ์จ์ฃผ๋ฉด ๋˜๋Š”๋ฐ,
๋‚˜๋Š” ํ”„๋กœ์ ํŠธ ํด๋” ์•ˆ์— ํ‚ค๋ฅผ ๋„ฃ์–ด์„œ ๊ด€๋ฆฌํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ ์–ด์ฃผ์—ˆ๋‹ค.
(๊ผญ .gitignore์— ํ‚ค๋ฅผ ์จ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!! ๊นƒํ—™์— ์˜ฌ๋ผ๊ฐ€๋ฉด ์•ˆ ๋ผ์š”!!!!!!!)

let serviceAccount = require(./๋‹ค์šด๋ฐ›์€serviceAccountKey๊ฐ’.json);


4. ์‹ค์ œ message ๋ณด๋‚ด๊ธฐ

// ๋ฉ”์„ธ์ง€ ๋‚ด์šฉ
const message = {
  notification: {
    title: notificationTitle,
    body: notificationContent,
  },
  token: token,
};

// ๋ฉ”์„ธ์ง€ ์ „์†ก
admin
  .messaging()
  .send(message)
  .then(function (response) {
    console.log("ํ‘ธ์‹œ์•Œ๋ฆผ ์ „์†ก ์„ฑ๊ณต", response);
  })
  .catch(function (error) {
    console.log("ํ‘ธ์‹œ์•Œ๋ฆผ ์ „์†ก ์‹คํŒจ");
  });
};

๐Ÿ‘† ์ด ์ฝ”๋“œ๊ฐ€ ์‹ค์ œ๋กœ fcm ์„œ๋ฒ„๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ์ฝ”๋“œ์ด๋‹ค. (unicast, ๋””๋ฐ”์ด์Šค ํ† ํฐ ํ•œ ๊ฐœ ํ•„์š”)
๋””๋ฐ”์ด์Šค ํ† ํฐ์€ ํ”„๋ก ํŠธ์—”ํŠธ ๊ฐœ๋ฐœ์ž ๋ถ„๋“ค๊ป˜ ์š”์ฒญํ•ด์„œ ํ‘ธ์‹œ ์•Œ๋ฆผ์ด ์ž˜ ๊ฐ€๋Š”์ง€ ํ…Œ์ŠคํŠธํ–ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ํ”„๋กœ์ ํŠธ ์ƒ์—์„œ๋Š” ์œ ์ €๊ฐ€ ๋กœ๊ทธ์ธํ•  ๋•Œ db์— ๊ทธ ์œ ์ €์˜ ๋””๋ฐ”์ด์Šค ํ† ํฐ์„ ์ €์žฅํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.
์–ด๋–ค ์œ ์ €์—๊ฒŒ ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ๋ณด๋‚ด์•ผ ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋ฉด์„œ ํ•ด๋‹น ์œ ์ €์˜ ๋””๋ฐ”์ด์Šค ํ† ํฐ์„ ๊ฐ€์ ธ์™€ token ๊ฐ’์œผ๋กœ ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค!


๋‚˜๋„์„ ๋ฐฐ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” api์— ์ด ์ฝ”๋“œ๋ฅผ ๋„ฃ์œผ๋ฉด ๋„ˆ๋ฌด ๊ธธ์–ด์ ธ์„œ lib์•ˆ์— ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ์ฝ”๋“œ๋ฅผ ๋ชจ๋“ˆํ™” ํ•ด ๋†“๊ณ , ํ•„์š”ํ•œ api์—์„œ ํ˜ธ์ถœํ•˜๋Š” ์‹์œผ๋กœ ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง ์ค‘์ด๋‹ค! ์„ ์ง„ํ–‰ํ–ˆ๋‹ค. (์„œ๋ฒ„ ์„ ๋ฐฐ๋“ค ์ตœ๊ณ  ๐Ÿ‘๐Ÿป)

๋ฐ‘์— ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด sendUnicast์™€ sendMulticast๊ฐ€ ์žˆ๋Š”๋ฐ

  • sendUnicast -> send(message) : ํ•˜๋‚˜์˜ device token์—๊ฒŒ ๋ณด๋ƒ„
  • sendMulticast -> sendMulticast(message) : ์—ฌ๋Ÿฌ ๊ฐœ์˜ device token๋“ค์—๊ฒŒ ํ•œ ๋ฒˆ์— ๋ณด๋ƒ„

์ด๋ ‡๊ฒŒ ๋‚˜๋ˆ ์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
์™œ multicast๋ฅผ ์ผ๋Š”์ง€๋Š” ๋ฐ‘์—์„œ ์„ค๋ช…ํ•˜๋„๋ก ํ•œ๋‹ค.

const admin = require("firebase-admin");

const sendUnicast = function (token, notificationTitle, notificationContent) {
  // ๋ฉ”์„ธ์ง€ ๋‚ด์šฉ
  const message = {
    notification: {
      title: notificationTitle,
      body: notificationContent,
    },
    token: token,
  };

  // ๋ฉ”์„ธ์ง€ ์ „์†ก
  admin
    .messaging()
    .send(message) // ํ•˜๋‚˜์˜ device token์—๊ฒŒ ๋ณด๋ƒ„
    .then(function (response) {
      console.log("ํ‘ธ์‹œ์•Œ๋ฆผ ์ „์†ก ์„ฑ๊ณต", response);
    })
    .catch(function (error) {
      console.log("ํ‘ธ์‹œ์•Œ๋ฆผ ์ „์†ก ์‹คํŒจ");
    });
};

const sendMulticast = function (tokens, notificationTitle, notificationContent) {
  // ๋Œ“๊ธ€์ด ์žˆ์„ ๋•Œ๋งŒ ํ‘ธ์‹œ์•Œ๋ฆผ ์ „์†ก, ๋Œ“๊ธ€์ด ์—†์„ ๊ฒฝ์šฐ tokens๊ฐ€ ๋นˆ ๋ฐฐ์—ด์ด๋ผ์„œ ์˜ค๋ฅ˜๋‚จ.

  if (tokens.length !== 0) {
    // ๋ฉ”์„ธ์ง€ ๋‚ด์šฉ
    const message = {
      notification: {
        title: notificationTitle,
        body: notificationContent,
      },
      tokens: tokens,
    };

    // ๋ฉ”์„ธ์ง€ ์ „์†ก
    admin
      .messaging()
      .sendMulticast(message) // ์—ฌ๋Ÿฌ๊ฐœ์˜ device token์—๊ฒŒ ํ•œ ๋ฒˆ์— ๋ณด๋ƒ„
      .then((response) => {
        console.log("ํ‘ธ์‹œ์•Œ๋ฆผ ์ „์†ก ์„ฑ๊ณต", response.successCount);
      })
      .catch(function (error) {
        console.log("ํ‘ธ์‹œ์•Œ๋ฆผ ์ „์†ก ์‹คํŒจ");
      });
  }
};

module.exports = {
  sendUnicast,
  sendMulticast,
};

โ€ผ๏ธ ์•„, ์ค‘๊ฐ„์— ์˜ค๋ฅ˜๋ฅผ ํ•œ ๋ฒˆ ๋งŒ๋‚ฌ๋Š”๋ฐ ๊ทธ ์ด์œ ๋Š”.... multicast์— ๋นˆ ๋ฐฐ์—ด์ด ๋“ค์–ด๊ฐ„ ๊ฒฝ์šฐ์—” empty array๋กœ ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์—ˆ๋‹ค...
๊ทธ๋ž˜์„œ tokens ๋ฐฐ์—ด ๊ธธ์ด๊ฐ€ 0์ธ ๊ฒฝ์šฐ๋Š” ๋ณด๋‚ด์ง€ ์•Š๋„๋ก ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์—ˆ๋‹ค.

 ๐Ÿ“Œ ๋‚˜๋„์„ ๋ฐฐ์— ์•Œ๋žŒ์ด ํ•„์š”ํ•œ ์ƒํ™ฉ! - ์™œ multicast๊ฐ€ ํ•„์š”ํ•ด?

๋‚˜๋„์„ ๋ฐฐ ์•ฑ์—๋Š” ํฌ๊ฒŒ

  1. ๋‚˜์—๊ฒŒ ์˜จ 1:1 ์งˆ๋ฌธ๊ธ€ ์•Œ๋ฆผ(๋งˆ์ดํŽ˜์ด์ง€์— 1:1 ์งˆ๋ฌธ๊ธ€์ด ์˜ฌ๋ผ์˜จ ๊ฒฝ์šฐ)
  2. ๋‹ต๊ธ€ ์•Œ๋ฆผ(๋‚ด๊ฐ€ ์“ด ๊ธ€์— ๋‹ต๊ธ€์ด ๋‹ฌ๋ฆฐ ๊ฒฝ์šฐ)
  3. ์ƒˆ ๋‹ต๊ธ€ ์•Œ๋ฆผ(๋‚ด๊ฐ€ ๋‹ต๊ธ€์„ ์“ด ํƒ€์ธ ๊ธ€์— ์ƒˆ ๋‹ต๊ธ€์ด ๋‹ฌ๋ฆฐ ๊ฒฝ์šฐ)

์ด๋ ‡๊ฒŒ ์„ธ ๊ฐ€์ง€์˜ ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ์žˆ๊ณ ,
์„ธ๋ถ€์ ์œผ๋กœ๋Š” 2, 3๋ฒˆ์€ ์งˆ๋ฌธ๊ธ€ / ์ •๋ณด๊ธ€๋กœ ๋‚˜๋ˆ„์–ด์ ธ์„œ ์ด 7๊ฐœ์˜ ์œ ํ˜•์ด ์žˆ๋‹ค.
์œ ํ˜•๋งˆ๋‹ค ์•Œ๋ฆผ ๋ฌธ๊ตฌ๋„ ๋‹ฌ๋ž๊ณ , ํŠนํžˆ ๊ฒŒ์‹œ๊ธ€์ธ ๊ฒฝ์šฐ๋Š” ํŠน์ • ์œ ์ € 1๋ช…์—๊ฒŒ ๋ณด๋‚ด๋Š” unicast์ธ์ง€ ๋‹ค์ˆ˜์—๊ฒŒ ๋ณด๋‚ด๋Š” multicast์ธ์ง€ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์ด ์ข€ ๊นŒ๋‹ค๋กœ์› ๋‹ค.


์˜ˆ๋ฅผ ๋“ค์–ด, ๋‚ด๊ฐ€ 1๋ฒˆ ๊ฒŒ์‹œ๋ฌผ์— ๋Œ“๊ธ€์„ ๋‹จ ๊ฒฝ์šฐ

  • 1๋ฒˆ ๊ฒŒ์‹œ๋ฌผ์„ ์“ด ์œ ์ €(์ž‘์„ฑ์ž)์—๊ฒŒ "์ž‘์„ฑํ•˜์‹  ์งˆ๋ฌธ๊ธ€์— ์ฃผํ˜„๋‹˜์ด ๋‹ต๊ธ€์„ ๋‚จ๊ฒผ์Šต๋‹ˆ๋‹ค." ๋˜๋Š” "์ž‘์„ฑํ•˜์‹  ์ •๋ณด๊ธ€์— ์ฃผํ˜„๋‹˜์ด ๋‹ต๊ธ€์„ ๋‚จ๊ฒผ์Šต๋‹ˆ๋‹ค."๋ผ๋Š” ์•Œ๋ฆผ์„ ๋ณด๋‚ธ๋‹ค.
  • 1๋ฒˆ ๊ฒŒ์‹œ๋ฌผ์— ๋Œ“๊ธ€์„ ๋‹ฌ์•˜๋˜ ์œ ์ €๋“ค์—๊ฒŒ "๋‹ต๊ธ€์„ ์ž‘์„ฑํ•˜์‹  ์งˆ๋ฌธ๊ธ€์— ์ฃผํ˜„๋‹˜์ด ๋‹ต๊ธ€์„ ๋‚จ๊ฒผ์Šต๋‹ˆ๋‹ค." ๋˜๋Š” "๋‹ต๊ธ€์„ ์ž‘์„ฑํ•˜์‹  ์ •๋ณด๊ธ€์— ์ฃผํ˜„๋‹˜์ด ๋‹ต๊ธ€์„ ๋‚จ๊ฒผ์Šต๋‹ˆ๋‹ค."

์ด๋Ÿฐ ์‹์œผ๋กœ ๋งŽ์€ case๊ฐ€ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ "์œ ์ €๋“ค" ์—๊ฒŒ ๋ณด๋‚ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— multicast๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.
๋งŒ์•ฝ, ๊ทธ๋ƒฅ send๋ฅผ ๋ฐ˜๋ณต๋ฌธ์„ ์‚ฌ์šฉํ•ด์„œ ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ์ „์†กํ•œ๋‹ค๋ฉด ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€์— ๋Œ“๊ธ€์„ ๋‹จ ์œ ์ €๋งˆ๋‹ค ํ‘ธ์‹œ์•Œ๋ฆผ์„ ๋ฐ›๋Š” ์‹œ๊ฐ„์ด ๋‹ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
(์—ฌ๋Ÿฌ ๋ช…์—๊ฒŒ ํ•œ ๋ฒˆ์— ๋ณด๋‚ผ ๋• multicast๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!)

 ๐Ÿ“Œ ๋งˆ์น˜๋ฉฐ

์‚ฌ์‹ค ๋‹ค๋ฅธ ํŒ€์›๋“ค์—๊ฒŒ ๋„์›€์ด ๋˜๊ณ  ์‹ถ์–ด์„œ ๋‹ค๋ฅธ API๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ํ‹ˆํ‹ˆ์ด ํ‘ธ์‹œ ์•Œ๋ฆผ ๊ณต๋ถ€๋ฅผ ํ•˜๋ฉด์„œ ์ฝ”๋“œ๋ฅผ ์งฐ์—ˆ๋Š”๋ฐ ๋””๋ฐ”์ด์Šค ํ† ํฐ์ด ์—†์–ด์„œ ์ง์ ‘ ์•Œ๋žŒ์ด ์˜ค๋Š” ๊ฒƒ์„ ๋ˆˆ์œผ๋กœ ํ™•์ธ ๋ชปํ•˜๋Š” ๊ฒŒ ์•„์‰ฌ์› ๋‹ค.
๋น„๋ก ์•ฑ์žผ ๊ธฐ๊ฐ„์ด ์–ผ๋งˆ ์•ˆ ๋‚จ์•„์„œ ์•Œ๋žŒ / ์ด๋ฉ”์ผ ์ธ์ฆ ์ด๋ ‡๊ฒŒ ๋‘ ๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ๋‚˜๋ˆ ์„œ ๋‹ด๋‹นํ•ด์„œ ๋‚˜๋Š” ์•Œ๋žŒ ์ฝ”๋“œ์— ์ง์ ‘์ ์ธ ์˜ํ–ฅ(?)์„ ๋ผ์น˜์ง„ ๋ชปํ–ˆ์ง€๋งŒ ํ˜ผ์ž ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์žฌ๋ฐŒ์—ˆ๋‹ค. ์ถ”๊ฐ€๋กœ ์‹œ๊ฐ„ ์„ค์ •ํ•ด์„œ ํ‘ธ์‹œ ์•Œ๋ฆผ ๋ณด๋‚ด๋Š” ๊ธฐ๋Šฅ๋„ ๊ณต๋ถ€ํ•ด์•ผ๊ฒ ๋‹ค!
๋‹ค์Œ ํ”„๋กœ์ ํŠธ์— ํ‘ธ์‹œ ์•Œ๋ฆผ์ด ์žˆ๋‹ค๋ฉด ํ˜ผ์ž ๊ตฌํ˜„ํ•  ์ˆ˜... ์žˆ์ง€ ์•Š์„๊นŒ..? ํ•˜ํ•˜

+ ์„œ๋ฒ„ ํŒ€์›๋“ค๊ณผ ์ฝ”๋“œ ๊ตฌํ˜„ ๊ด€๋ จ ํšŒ์˜ํ•  ๋•Œ ๋‹ค๋“ค ํ‘ธ์‹œ ์•Œ๋ฆผ์ด ํ•ด๋ณด๊ณ  ์‹ถ๋‹ค๊ณ  ํ•ด์„œ ๊ฐ์ž ์ฝ”๋“œ๋ฅผ ์งœ๋ฉฐ ๊ณต๋ถ€๋ฅผ ํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋Š”๋ฐ, ๋ชจ๋‘ ์—ด์‹ฌํžˆ ํ•ด์ค˜์„œ ๊ณ ๋งˆ์› ๋‹ค. ๋‹ค๋“ค ๊ณ ์ƒํ–ˆ์–ด์š” ๐Ÿ”ฅ

+ Recent posts