Push bildirishnomalar — expo-notifications
Muammodan boshlaylik
Buyurtma holati o'zgardi: "Kuryer yo'lga chiqdi". Foydalanuvchi buni qanday biladi? Ilova yopiq. U ilovani o'zi ochib, tekshirishi kerakmi?
Push bildirishnoma — ilova yopiq bo'lsa ham, server telefon ekraniga xabar yuboradi. Bosilganda — ilova aynan kerakli ekranda ochiladi.
Ikki tur:
- Lokal — ilovaning o'zi rejalashtiradi ("Har kuni 20:00 da suv ichishni eslatish")
- Remote (push) — serverdan keladi ("Buyurtmangiz yo'lda")
O'rnatish
npx expo install expo-notifications expo-device expo-constants
"plugins": [
["expo-notifications", { "icon": "./assets/images/notification-icon.png", "color": "#0284c7" }]
]
Android bildirishnoma ikonkasi — oq rangli, shaffof fonli PNG (tizim uni o'zi bo'yaydi).
[!WARNING] Remote push bildirishnomalar Expo Go da Android uchun ishlamaydi (SDK 53 dan beri). Sinash uchun development build kerak (48-dars). Lokal bildirishnomalar Expo Go da ishlaydi. Push — faqat haqiqiy qurilmada, emulyatorda emas.
Ilova ochiq bo'lganda xatti-harakat
Standart holatda ilova ochiq paytda kelgan bildirishnoma ko'rsatilmaydi. Ko'rsatish uchun — modul darajasida, bir marta:
// app/_layout.tsx (komponentdan tashqarida)
import * as Notifications from 'expo-notifications';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowBanner: true,
shouldShowList: true,
shouldPlaySound: true,
shouldSetBadge: false,
}),
});
Lokal bildirishnoma
async function eslatmaQosh() {
const { status } = await Notifications.requestPermissionsAsync();
if (status !== 'granted') return;
// 5 soniyadan keyin
await Notifications.scheduleNotificationAsync({
content: {
title: '💧 Suv ichish vaqti',
body: "Bugun hali 3 stakan qoldi",
data: { url: '/suv' },
},
trigger: { type: Notifications.SchedulableTriggerInputTypes.TIME_INTERVAL, seconds: 5 },
});
// Har kuni 20:00 da
await Notifications.scheduleNotificationAsync({
content: { title: 'Kunlik hisobot', body: 'Bugungi natijalaringizni ko\'ring' },
trigger: { type: Notifications.SchedulableTriggerInputTypes.DAILY, hour: 20, minute: 0 },
});
}
await Notifications.cancelAllScheduledNotificationsAsync(); // hammasini bekor qilish
Server kerak emas — eslatmalar, taymerlar, odat kuzatuvchilar uchun.
Remote push — umumiy sxema
┌──────────┐ 1. token so'rash ┌──────────────┐
│ Ilova │ ─────────────────→ │ Expo / FCM / │
│ │ ←───────────────── │ APNs │
└────┬─────┘ 2. ExponentPushToken[...] └──────┬───────┘
│ 3. tokenni serverga yuborish │
▼ │ 5. telefonga yetkazish
┌──────────┐ 4. "shu tokenga xabar yubor" │
│ Server │ ──────────────────────────────────→┘
└──────────┘
Apple (APNs) va Google (FCM) ning push tizimlari murakkab. Expo Push Service ular ustidagi yagona qatlam: siz bitta API va bitta token turi bilan ishlaysiz.
1-2. Token olish
// lib/push.ts
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
import Constants from 'expo-constants';
import { Platform } from 'react-native';
export async function pushTokenOl(): Promise<string | null> {
if (!Device.isDevice) return null; // emulyatorda ishlamaydi
if (Platform.OS === 'android') {
await Notifications.setNotificationChannelAsync('buyurtmalar', {
name: 'Buyurtmalar holati',
importance: Notifications.AndroidImportance.HIGH,
});
}
const { status: mavjud } = await Notifications.getPermissionsAsync();
let status = mavjud;
if (mavjud !== 'granted') {
status = (await Notifications.requestPermissionsAsync()).status;
}
if (status !== 'granted') return null;
const projectId = Constants.expoConfig?.extra?.eas?.projectId ?? Constants.easConfig?.projectId;
const { data } = await Notifications.getExpoPushTokenAsync({ projectId });
return data; // "ExponentPushToken[xxxxxx]"
}
- Android kanallari — foydalanuvchi har bir turni sozlamalarda alohida o'chira oladi ("Buyurtmalar" — ha, "Aksiyalar" — yo'q). Android 8+ da majburiy
projectId—eas initdan keyinapp.jsonga yoziladi (48-dars)
3. Serverga yuborish
// Kirgandan keyin
const token = await pushTokenOl();
if (token) await apiPost('/qurilmalar', { token, platforma: Platform.OS });
Server tokenni foydalanuvchiga bog'lab saqlaydi. Bitta foydalanuvchida bir nechta qurilma bo'lishi mumkin — har biri o'z tokeni bilan. Chiqishda — tokenni serverdan o'chiring.
4. Serverdan yuborish
curl -X POST https://exp.host/--/api/v2/push/send \
-H "Content-Type: application/json" \
-d '{
"to": "ExponentPushToken[xxxxxx]",
"title": "Buyurtmangiz yo'\''lda 🚚",
"body": "Kuryer 20-30 daqiqada yetib keladi",
"data": { "url": "/buyurtma/1043" },
"channelId": "buyurtmalar"
}'
Node.js da — expo-server-sdk paketi (100 tadan to'plab yuborish, xatolarni qayta ishlash). Sinash uchun — https://expo.dev/notifications dagi vosita.
Javobdagi DeviceNotRegistered xatosi — foydalanuvchi ilovani o'chirgan. Bunday tokenni bazadan o'chiring.
Bildirishnoma bosilganda — kerakli ekranga
// app/_layout.tsx
import { router } from 'expo-router';
function useBildirishnomaNavigatsiya() {
useEffect(() => {
function ochish(n: Notifications.Notification) {
const url = n.request.content.data?.url;
if (typeof url === 'string' && url.startsWith('/')) router.push(url);
}
// Ilova YOPIQ bo'lganda bosilgan bildirishnoma (ilova shu bilan ochildi)
const oxirgi = Notifications.getLastNotificationResponse();
if (oxirgi) ochish(oxirgi.notification);
// Ilova ochiq / fonda bo'lganda bosilgan
const sub = Notifications.addNotificationResponseReceivedListener((r) => ochish(r.notification));
return () => sub.remove();
}, []);
}
data.url — Expo Router yo'li (29-dars). startsWith('/') — faqat ichki yo'llar; serverdan kelgan ma'lumotga ham ko'r-ko'rona ishonmang.
Ilova ochiq paytda kelgan bildirishnomaga darhol javob (masalan, buyurtmalar ro'yxatini yangilash):
Notifications.addNotificationReceivedListener(() => {
queryClient.invalidateQueries({ queryKey: ['buyurtmalar'] });
});
Yaxshi amaliyot
- Ruxsatni kontekstda so'rang (38-dars): birinchi buyurtmadan keyin "Buyurtma holatini bildirishnoma orqali kuzatasizmi?" — ochilishi bilan emas
- Foydali bo'lsin: buyurtma holati, xabar, eslatma. Har kuni reklama — foydalanuvchi bildirishnomalarni o'chiradi yoki ilovani o'chirib tashlaydi
- Kanallar bilan turlarni ajrating — foydalanuvchi reklamani o'chirsa ham, buyurtma xabarlari qolsin
- Matn — mustaqil: "Yangi xabar" emas, "Malika: Buyurtma qachon keladi?"
- Har bir bildirishnoma — aniq ekranga olib borsin
Nima uchun shunday?
Nima uchun ilova o'zi serverga doimiy ulanib, xabarlarni kutib turmaydi — push xizmati nima uchun kerak?
Batareya. Agar telefondagi har bir ilova o'z serveriga doimiy ulanishni ushlab tursa — 50 ta ilova, 50 ta ulanish, telefon bir necha soatda o'chadi. Shuning uchun iOS va Android fon ilovalarini qattiq cheklaydi. Push tizimi — operatsion tizimning yagona doimiy ulanishi: Apple yoki Google serveriga bitta ulanish orqali barcha ilovalar uchun xabarlar keladi. Ilova esa faqat xabar kelganda "uyg'otiladi".
Xulosa
Eslab qoling:
- Lokal —
scheduleNotificationAsync(eslatmalar); remote — serverdan setNotificationHandler— ilova ochiq paytda ko'rsatish- Token: ruxsat →
getExpoPushTokenAsync({ projectId })→ serverga - Android — kanallar majburiy; ikonka — oq va shaffof
- Server:
exp.host/--/api/v2/push/send;DeviceNotRegistered— tokenni o'chirish data.url+addNotificationResponseReceivedListener+getLastNotificationResponse— bosilganda ekranga- Remote push — development build va haqiqiy qurilma
- Kam, foydali, aniq; ruxsatni kontekstda so'rang
Keyingi dars
43-dars: Haptics, Share, Clipboard, Linking