Урок 04

Push-уведомления

Уведомления удерживают пользователя. Бывают локальные и push (с сервера).

Expo Notifications

npx expo install expo-notifications expo-device expo-constants

Разрешение

import * as Notifications from 'expo-notifications';

const { status } = await Notifications.requestPermissionsAsync();
if (status !== 'granted') return;

Получение токена

import Constants from 'expo-constants';

async function registerForPush() {
    const { status } = await Notifications.requestPermissionsAsync();
    if (status !== 'granted') return null;

    const projectId = Constants.expoConfig?.extra?.eas?.projectId;
    const token = (await Notifications.getExpoPushTokenAsync({ projectId })).data;

    await api.post('/devices', { token, platform: Platform.OS });
    return token;
}

Токен отправляется на сервер. Сервер шлёт уведомления через Expo Push API.

Настройка Android-канала

if (Platform.OS === 'android') {
    await Notifications.setNotificationChannelAsync('default', {
        name: 'Основной',
        importance: Notifications.AndroidImportance.HIGH,
        vibrationPattern: [0, 250, 250, 250],
        lightColor: '#c1442e',
    });
}

Обработчик в приложении

Notifications.setNotificationHandler({
    handleNotification: async () => ({
        shouldShowAlert: true,
        shouldPlaySound: true,
        shouldSetBadge: true,
    }),
});

Слушатели

useEffect(() => {
    const receivedSub = Notifications.addNotificationReceivedListener((notification) => {
        console.log('получено', notification);
    });

    const responseSub = Notifications.addNotificationResponseReceivedListener((response) => {
        const data = response.notification.request.content.data;
        // навигация по data
        if (data.type === 'post') {
            navigation.navigate('PostDetails', { id: data.id });
        }
    });

    return () => {
        receivedSub.remove();
        responseSub.remove();
    };
}, []);

Локальные уведомления

await Notifications.scheduleNotificationAsync({
    content: {
        title: 'Напоминание',
        body: 'Не забудьте про задачу',
        data: { taskId: 5 },
    },
    trigger: { seconds: 60 },
});

С датой:

trigger: { date: new Date(Date.now() + 60 * 60 * 1000) },

Ежедневно:

trigger: { hour: 9, minute: 0, repeats: true },

Бейдж

await Notifications.setBadgeCountAsync(5);

Отмена

await Notifications.cancelAllScheduledNotificationsAsync();

Отправка с сервера

Сервер отправляет через Expo Push API:

curl -X POST https://exp.host/--/api/v2/push/send \
  -H "Content-Type: application/json" \
  -d '{
    "to": "ExponentPushToken[xxx]",
    "title": "Новое сообщение",
    "body": "У вас 1 новое сообщение",
    "data": { "type": "chat", "chatId": 5 }
  }'

Или через Laravel:

use Illuminate\Support\Facades\Http;

Http::post('https://exp.host/--/api/v2/push/send', [
    'to' => $deviceToken,
    'title' => 'Новое сообщение',
    'body' => 'У вас 1 новое сообщение',
    'data' => ['type' => 'chat', 'chatId' => 5],
]);

Deep link из уведомления

responseSub = Notifications.addNotificationResponseReceivedListener((response) => {
    const url = response.notification.request.content.data.url;
    if (url) Linking.openURL(url);
});

Отладка

В Expo Go push не работают с реальным сервером. Нужен dev build или production build.

Итоги

  • expo-notifications
  • Разрешение обязательно
  • getExpoPushTokenAsync для токена
  • Каналы на Android
  • Слушатели для получения и нажатия
  • Локальные через scheduleNotificationAsync
  • Сервер шлёт через Expo Push API