Mostrare notifiche locali in Flutter con flutter_local_notifications
GuideIntermedio35 min Flutter 3.x

Mostrare notifiche locali in Flutter con flutter_local_notifications

Le notifiche locali permettono alla tua app di comunicare con l'utente anche quando non è in primo piano, senza la necessità di un server remoto. Sono perfette per promemoria, allarmi, conferme e avvisi pianificati.

In questo tutorial vedremo come integrare il pacchetto flutter_local_notifications, configurarlo correttamente per Android e iOS, mostrare una notifica immediata e programmarne una nel futuro usando timezone.

Prerequisiti: conoscenza di base di Flutter e di come modificare i file nativi AndroidManifest.xml e Info.plist.

  1. 1

    Aggiungere le dipendenze

    Apri il file pubspec.yaml e aggiungi i pacchetti flutter_local_notifications per gestire le notifiche e timezone per la programmazione basata sui fusi orari.

    Dopo aver salvato, esegui flutter pub get dal terminale.

    dependencies:
      flutter:
        sdk: flutter
      flutter_local_notifications: ^17.2.3
      timezone: ^0.9.4

    Risultato atteso

    I pacchetti vengono scaricati e risultano disponibili nel progetto.

  2. 2

    Configurare i permessi nativi

    Per Android, apri android/app/src/main/AndroidManifest.xml e aggiungi i permessi necessari (per le notifiche e quelle esatte programmate) dentro il tag <manifest>.

    Su Android 13+ è obbligatorio anche il permesso POST_NOTIFICATIONS.

    Per iOS i permessi vengono richiesti a runtime, quindi non serve modificare l'Info.plist, ma assicurati di abilitare le notifiche nelle capability del progetto Xcode.

    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    Risultato atteso

    L'app dispone dei permessi per mostrare e programmare notifiche.

  3. 3

    Creare un servizio per le notifiche

    Per mantenere il codice organizzato, creiamo una classe NotificationService che incapsula l'istanza del plugin e la logica di inizializzazione. Inizializziamo anche il database dei fusi orari di timezone.

    Nel metodo init() configuriamo le impostazioni per Android (specificando l'icona dell'app) e per iOS.

    import 'package:flutter_local_notifications/flutter_local_notifications.dart';
    import 'package:timezone/data/latest.dart' as tz;
    import 'package:timezone/timezone.dart' as tz;
    
    class NotificationService {
      static final _plugin = FlutterLocalNotificationsPlugin();
    
      static Future<void> init() async {
        tz.initializeTimeZones();
    
        const androidSettings =
            AndroidInitializationSettings('@mipmap/ic_launcher');
        const iosSettings = DarwinInitializationSettings();
    
        const settings = InitializationSettings(
          android: androidSettings,
          iOS: iosSettings,
        );
    
        await _plugin.initialize(settings);
      }
    }

    Risultato atteso

    La classe NotificationService è pronta per essere inizializzata.

  4. 4

    Inizializzare il servizio e richiedere i permessi

    Nel main() rendiamo asincrona la funzione, assicuriamoci che i binding di Flutter siano inizializzati e chiamiamo NotificationService.init().

    Su Android 13+ e iOS è necessario richiedere esplicitamente il permesso di mostrare notifiche. Aggiungiamo un metodo dedicato nel servizio.

    // Dentro NotificationService
    static Future<void> requestPermissions() async {
      await _plugin
          .resolvePlatformSpecificImplementation<
              AndroidFlutterLocalNotificationsPlugin>()
          ?.requestNotificationsPermission();
    
      await _plugin
          .resolvePlatformSpecificImplementation<
              IOSFlutterLocalNotificationsPlugin>()
          ?.requestPermissions(alert: true, badge: true, sound: true);
    }
    
    // main.dart
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await NotificationService.init();
      await NotificationService.requestPermissions();
      runApp(const MyApp());
    }

    Risultato atteso

    All'avvio l'app richiede all'utente il permesso di inviare notifiche.

  5. 5

    Mostrare una notifica immediata

    Aggiungiamo al servizio un metodo showNotification che definisce i dettagli della notifica. Su Android è obbligatorio specificare un channel (id, nome e descrizione), mentre su iOS i dettagli sono più semplici.

    Il metodo show accetta un id univoco, un titolo, un corpo e i dettagli della piattaforma.

    static Future<void> showNotification({
      required int id,
      required String title,
      required String body,
    }) async {
      const androidDetails = AndroidNotificationDetails(
        'canale_principale',
        'Notifiche principali',
        channelDescription: 'Canale per le notifiche generali',
        importance: Importance.max,
        priority: Priority.high,
      );
      const iosDetails = DarwinNotificationDetails();
    
      const details = NotificationDetails(
        android: androidDetails,
        iOS: iosDetails,
      );
    
      await _plugin.show(id, title, body, details);
    }

    Risultato atteso

    Chiamando il metodo viene mostrata immediatamente una notifica di sistema.

  6. 6

    Programmare una notifica nel futuro

    Per le notifiche pianificate usiamo zonedSchedule, che richiede un'istanza TZDateTime. Calcoliamo l'orario futuro a partire da tz.local.

    Il parametro androidScheduleMode con exactAllowWhileIdle garantisce la consegna anche in modalità doze. matchDateTimeComponents può essere usato per ripetizioni giornaliere o settimanali.

    static Future<void> scheduleNotification({
      required int id,
      required String title,
      required String body,
      required Duration delay,
    }) async {
      final scheduledDate = tz.TZDateTime.now(tz.local).add(delay);
    
      const details = NotificationDetails(
        android: AndroidNotificationDetails(
          'canale_programmate',
          'Notifiche programmate',
          importance: Importance.max,
          priority: Priority.high,
        ),
        iOS: DarwinNotificationDetails(),
      );
    
      await _plugin.zonedSchedule(
        id,
        title,
        body,
        scheduledDate,
        details,
        androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
      );
    }

    Risultato atteso

    Una notifica viene consegnata dopo l'intervallo di tempo specificato.

  7. 7

    Collegare i metodi all'interfaccia

    Infine creiamo una semplice UI con due pulsanti: uno per mostrare subito una notifica e uno per programmarla tra 5 secondi. Così potrai testare entrambi i comportamenti.

    Ricorda di usare id diversi per evitare che una notifica sovrascriva l'altra.

    class HomePage extends StatelessWidget {
      const HomePage({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('Notifiche locali')),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () => NotificationService.showNotification(
                    id: 0,
                    title: 'Ciao!',
                    body: 'Questa è una notifica immediata',
                  ),
                  child: const Text('Notifica immediata'),
                ),
                ElevatedButton(
                  onPressed: () => NotificationService.scheduleNotification(
                    id: 1,
                    title: 'Promemoria',
                    body: 'Sono passati 5 secondi!',
                    delay: const Duration(seconds: 5),
                  ),
                  child: const Text('Programma tra 5s'),
                ),
              ],
            ),
          ),
        );
      }
    }

    Risultato atteso

    L'app mostra due pulsanti funzionanti che attivano notifiche immediate e programmate.

CondividiXLinkedInFacebookWhatsApp

Commenti (0)

Ancora nessun commento. Inizia tu!