Kurs React Native · Moduł 7: Powiadomienia

Projekt: System powiadomień Atlantydy

2 min czytania ·

Stwórzmy kompletny system powiadomień!

import { useEffect, useRef, useState } from 'react';
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
import { Platform } from 'react-native';

// Konfiguracja
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowBanner: true,
    shouldShowList: true,
    shouldPlaySound: true,
    shouldSetBadge: true,
  }),
});

// Hook do powiadomień
export function useNotifications() {
  const [expoPushToken, setExpoPushToken] = useState<string>('');
  const [notification, setNotification] = useState<Notifications.Notification>();
  const notificationListener = useRef<Notifications.Subscription>();
  const responseListener = useRef<Notifications.Subscription>();

  useEffect(() => {
    // Rejestracja
    registerForPushNotificationsAsync().then((token) => {
      if (token) setExpoPushToken(token);
    });

    // Setup kanałów Android
    setupAndroidChannels();

    // Listenery
    notificationListener.current = Notifications.addNotificationReceivedListener(
      setNotification
    );

    responseListener.current = Notifications.addNotificationResponseReceivedListener(
      (response) => {
        handleNotificationResponse(response);
      }
    );

    return () => {
      notificationListener.current?.remove();
      responseListener.current?.remove();
    };
  }, []);

  return { expoPushToken, notification };
}

async function registerForPushNotificationsAsync() {
  if (!Device.isDevice) {
    console.log('Push notifications wymagają urządzenia');
    return;
  }

  const { status: existingStatus } = await Notifications.getPermissionsAsync();
  let finalStatus = existingStatus;

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

  if (finalStatus !== 'granted') {
    return;
  }

  const token = await Notifications.getExpoPushTokenAsync();
  return token.data;
}

async function setupAndroidChannels() {
  if (Platform.OS !== 'android') return;

  await Notifications.setNotificationChannelAsync('default', {
    name: 'Domyślne',
    importance: Notifications.AndroidImportance.MAX,
  });

  await Notifications.setNotificationChannelAsync('reminders', {
    name: 'Przypomnienia',
    importance: Notifications.AndroidImportance.HIGH,
  });
}

function handleNotificationResponse(response: Notifications.NotificationResponse) {
  const data = response.notification.request.content.data;
  // Nawigacja na podstawie data
  console.log('Notification data:', data);
}

// Serwisy powiadomień
export const NotificationService = {
  // Lokalne powiadomienie
  sendLocal: async (title: string, body: string, data?: object) => {
    return Notifications.scheduleNotificationAsync({
      content: { title, body, data, sound: true },
      trigger: null,
    });
  },

  // Przypomnienie
  scheduleReminder: async (title: string, body: string, date: Date) => {
    return Notifications.scheduleNotificationAsync({
      content: { title, body },
      trigger: date,
    });
  },

  // Codzienne przypomnienie
  scheduleDailyReminder: async (title: string, body: string, hour: number, minute: number) => {
    return Notifications.scheduleNotificationAsync({
      content: { title, body },
      trigger: { hour, minute, repeats: true },
    });
  },

  // Anuluj wszystkie
  cancelAll: async () => {
    await Notifications.cancelAllScheduledNotificationsAsync();
  },

  // Wyczyść badge
  clearBadge: async () => {
    await Notifications.setBadgeCountAsync(0);
  },
};

Ten system obsługuje rejestrację, lokalne powiadomienia, push notifications i kanały Android!

Kod do tej lekcji: App.tsx
import { View, Text, Button, StyleSheet } from 'react-native';
import * as Notifications from 'expo-notifications';

// Projekt: kompletny serwis powiadomień Atlantydy
export const NotificationService = {
  // Lokalne powiadomienie natychmiastowe
  sendLocal: async (title: string, body: string, data?: object) => {
    // TODO: wywołaj scheduleNotificationAsync z trigger: null
    return Notifications.scheduleNotificationAsync({
      content: { title, body, data, sound: true },
      trigger: null,
    });
  },

  // Przypomnienie na konkretną datę
  scheduleReminder: async (title: string, body: string, date: Date) => {
    // TODO: ustaw trigger na przekazaną datę
    return Notifications.scheduleNotificationAsync({
      content: { title, body },
      trigger: date,
    });
  },

  // Codzienne przypomnienie o danej godzinie
  scheduleDailyReminder: async (title: string, body: string, hour: number, minute: number) => {
    // TODO: ustaw trigger { hour, minute, repeats: true }
    return Notifications.scheduleNotificationAsync({
      content: { title, body },
      // TODO: uzupełnij trigger z repeats: true
      trigger: { hour, minute, repeats: false },
    });
  },

  // Anuluj wszystkie zaplanowane powiadomienia
  cancelAll: async () => {
    // TODO: wywołaj cancelAllScheduledNotificationsAsync()
  },

  // Wyczyść badge na ikonie aplikacji
  clearBadge: async () => {
    // TODO: ustaw badge na 0 przez setBadgeCountAsync(0)
  },
};

export default function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>System powiadomień Atlantydy</Text>
      <Button
        title="Wyślij lokalne"
        onPress={() => NotificationService.sendLocal('Atlantyda', 'Posejdon cię wzywa!')}
      />
      <Button title="Wyczyść badge" onPress={NotificationService.clearBadge} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#1a5276', gap: 16, padding: 20 },
  title: { fontSize: 22, color: '#fff', textAlign: 'center' },
});

Hasła z dokumentacji w tej lekcji

Widzisz błąd w tej lekcji?

Zadania praktyczne w grze

  • Edytor kodu

    Uzupełnij kod kompletnego serwisu.

Przydatne artykuły