Push Notification — Firebase Cloud Messaging

~20 daq · Express · Email va Xabarlar

Muammodan boshlaylik

Foydalanuvchi ilovani yopdi. Lekin unga yangi xabar keldi — bilishi kerak. SMS yuborasizmi? Qimmat. Email? Ko'rmaydi.

Push notification — telefon ekranida chiqadigan bildirishnoma. Telegram, Instagram, delivery ilovalari shunday ishlaydi. Ilovani ochmasdan ham ko'rasiz.


Push Notification qanday ishlaydi?

Sizning server        FCM (Firebase)        Foydalanuvchi qurilmasi
    |                      |                        |
    | Ilovani ochganda:    |                        |
    |                      |<-- token so'rash ------|
    |                      |--- token berildi ----->|
    |<-- token saqlash ----|                        |
    |                      |                        |
    | Xabar kelganda:      |                        |
    |--- push yubor ------>|                        |
    |                      |--- bildirish --------->|
    |                      |        (telefon ekrani)|

FCM (Firebase Cloud Messaging) — vositachi. Sizning serveringiz FCM ga xabar yuboradi, FCM esa foydalanuvchining telefoniga yetkazadi. Telefon o'chiq bo'lmasa ham — saqlab qo'yadi.


FCM token nima?

Har bir qurilma — noyob token. Xuddi pochta adresi kabi. Siz shu adresga xabar jo'natasiz — FCM aniq shu qurilmaga yetkazadi.

Token:

  • Ilova o'rnatilganda FCM beradi
  • Ilova qayta o'rnatilsa yoki brauzert tozalansa — yangi token
  • Sizning serveringiz uni DB da saqlashi kerak

Firebase loyiha yaratish

  1. console.firebase.google.com
  2. Yangi loyiha → nom bering
  3. Project Settings → Service Accounts → Generate new private key
  4. JSON fayl yuklab olinadi — bu maxfiy kalit
FIREBASE_PROJECT_ID=loyiha-id
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n..."
FIREBASE_CLIENT_EMAIL=firebase-adminsdk@loyiha.iam.gserviceaccount.com

⚠️ JSON faylni Git ga qo'shmang! .gitignore ga qo'shing yoki environment variable dan foydalaning.


O'rnatish

npm install firebase-admin

FCM sozlash

import admin from 'firebase-admin';

admin.initializeApp({
  credential: admin.credential.cert({
    projectId:   process.env.FIREBASE_PROJECT_ID,
    privateKey:  process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n'), // ← muhim!
    clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
  }),
});

💡 replace(/\\n/g, '\n') — .env faylda yangi qator \n sifatida yoziladi. Firebase esa haqiqiy yangi qator kutadi.


Push notification yuborish

const pushYuborish = async (token, { sarlavha, matn, malumotlar }) => {
  await admin.messaging().send({
    token,               // ← qaysi qurilmaga
    notification: {
      title: sarlavha,  // ← bildirishnoma sarlavhasi
      body: matn,        // ← bildirishnoma matni
    },
    data: malumotlar,   // ← ilovaga qo'shimcha ma'lumot (ixtiyoriy)
  });
};

// Ishlatish
await pushYuborish(foydalanuvchi.fcmToken, {
  sarlavha: 'Yangi xabar',
  matn: 'Ali sizga xabar yubordi',
  malumotlar: { xabarId: '123', tur: 'chat' },
});

Token ni DB da saqlash

Ilova (frontend) FCM tokenni serverga yuboradi, server DB ga saqlaydi:

// Server — tokenni saqlash
router.post('/fcm-token', authMiddleware, async (req, res) => {
  const { token } = req.body;

  await db.users.update(
    { fcmToken: token },
    { where: { id: req.user.id } },
  );

  res.json({ xabar: 'Token saqlandi' });
});

Ko'p qurilmaga yuborish

Bir guruh foydalanuvchilarga — token massivi bilan:

const kopQurilmaPush = async (tokenlar, { sarlavha, matn }) => {
  if (tokenlar.length === 0) return;

  await admin.messaging().sendEachForMulticast({
    tokens: tokenlar,        // ← token massivi (max 500)
    notification: { title: sarlavha, body: matn },
  });
};

// Ishlatish
const tokenlar = users.map((u) => u.fcmToken).filter(Boolean);
await kopQurilmaPush(tokenlar, {
  sarlavha: 'Yangilik!',
  matn: 'Yangi kurs qo\'shildi',
});

Topic — mavzu bo'yicha yuborish

Barcha foydalanuvchilarga emas — ma'lum guruhga:

// Foydalanuvchini mavzuga qo'shish
await admin.messaging().subscribeToTopic(token, 'yangiliklar');

// Mavzu bo'yicha yuborish
await admin.messaging().send({
  topic: 'yangiliklar',
  notification: {
    title: 'Yangi kurs chiqdi!',
    body: 'Express.js kursi yangilandi',
  },
});

💡 Topic — yangiliklarni obuna bo'lgan foydalanuvchilarga, sport yangiliklari, promo xabarlar uchun mos. Individual foydalanuvchiga — token.


Tez-tez uchraydigan xatolar

1. FIREBASE_PRIVATE_KEY yangi qator muammosi

// ❌ — \n literal sifatida qoladi
credential: admin.credential.cert({
  privateKey: process.env.FIREBASE_PRIVATE_KEY,
})

// ✅ — haqiqiy yangi qatarga aylantirish
privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n'),

2. Eskirgan token xatosi

messaging/registration-token-not-registered

Sababi: foydalanuvchi ilovani o'chirib o'rnatdi yoki ruxsatni bekor qildi.

Yechim: bu tokenni DB dan o'chiring — yuqoridagi eskirganTokenlar misoli.

3. Token yo'q foydalanuvchiga yuborish

// ❌ — token null bo'lsa crash
await pushYuborish(foydalanuvchi.fcmToken, xabar);

// ✅ — tekshirish
if (foydalanuvchi.fcmToken) {
  await pushYuborish(foydalanuvchi.fcmToken, xabar);
}

Xulosa

  • FCM — Google ning push notification xizmati; server → FCM → qurilma
  • Har qurilma — noyob token; DB da saqlang, token null bo'lsa tekshiring
  • admin.messaging().send({ token, notification }) — bir qurilmaga
  • sendEachForMulticast({ tokens }) — ko'p qurilmaga (max 500)
  • Topic — guruh obunasi (yangiliklar, promo)
  • FIREBASE_PRIVATE_KEY dagi \\n ni \n ga aylantiring

Keyingi dars: 50-dars: Jest — o'rnatish, birinchi test, describe, it, expect