Rilevare la connessione di rete in Flutter con connectivity_plus
GuideIntermedio30 min Flutter 3.x

Rilevare la connessione di rete in Flutter con connectivity_plus

Perché monitorare la connessione

Quasi tutte le app moderne dipendono dalla rete: caricano dati da API, sincronizzano contenuti o autenticano gli utenti. Se il dispositivo perde la connessione, offrire un feedback chiaro migliora enormemente l'esperienza utente.

In questo tutorial useremo il pacchetto ufficiale connectivity_plus per rilevare i cambiamenti di stato della rete (Wi‑Fi, dati mobili, assenza di connessione) e mostreremo un banner reattivo quando l'utente va offline.

Attenzione: connectivity_plus indica se il dispositivo è collegato a una rete, non se ha realmente accesso a Internet. Vedremo come integrare un semplice controllo di raggiungibilità reale.

  1. 1

    Aggiungere le dipendenze

    Apri il file pubspec.yaml e aggiungi il pacchetto connectivity_plus. Per il controllo di raggiungibilità reale useremo anche http.

    Dopo aver salvato, esegui il comando di installazione dal terminale.

    dependencies:
      flutter:
        sdk: flutter
      connectivity_plus: ^6.0.5
      http: ^1.2.2

    Risultato atteso

    Il comando `flutter pub get` scarica i pacchetti senza errori.

  2. 2

    Creare un servizio per la connettività

    Isoliamo la logica in una classe dedicata. Il metodo checkConnection verifica lo stato attuale, mentre onConnectivityChanged espone uno Stream che emette un valore ad ogni cambiamento di rete.

    Nota che dalla versione 6.x, checkConnectivity() restituisce una List<ConnectivityResult> perché un dispositivo può avere più interfacce attive.

    import 'package:connectivity_plus/connectivity_plus.dart';
    
    class ConnectivityService {
      final Connectivity _connectivity = Connectivity();
    
      // Stream dei cambiamenti di stato della rete
      Stream<List<ConnectivityResult>> get onStatusChange =>
          _connectivity.onConnectivityChanged;
    
      // Verifica se almeno una interfaccia di rete è attiva
      Future<bool> get isConnected async {
        final results = await _connectivity.checkConnectivity();
        return _hasConnection(results);
      }
    
      bool _hasConnection(List<ConnectivityResult> results) {
        return !results.contains(ConnectivityResult.none) && results.isNotEmpty;
      }
    }

    Risultato atteso

    La classe compila correttamente ed espone uno stream e un getter per lo stato della rete.

  3. 3

    Verificare l'accesso reale a Internet

    Come detto, essere collegati a una rete non garantisce l'accesso a Internet (es. Wi‑Fi senza uscita). Aggiungiamo un metodo che tenta una richiesta HTTP leggera per confermare la raggiungibilità reale.

    Usiamo un timeout breve per non bloccare l'interfaccia in caso di rete lenta.

    import 'package:http/http.dart' as http;
    
    extension RealConnectivity on ConnectivityService {
      Future<bool> hasInternetAccess() async {
        // Prima controlla se c'è una interfaccia attiva
        if (!await isConnected) return false;
    
        try {
          final response = await http
              .head(Uri.parse('https://clients3.google.com/generate_204'))
              .timeout(const Duration(seconds: 3));
          return response.statusCode == 204 || response.statusCode == 200;
        } catch (_) {
          return false;
        }
      }
    }

    Risultato atteso

    Il metodo restituisce `true` solo quando esiste una connessione realmente funzionante.

  4. 4

    Creare un widget banner reattivo

    Costruiamo un widget che ascolta lo stream di connettività tramite StreamBuilder e mostra un banner rosso quando l'utente è offline. Utilizziamo AnimatedContainer per una transizione fluida.

    Il banner si posiziona in cima al contenuto grazie a una Column.

    import 'package:flutter/material.dart';
    import 'package:connectivity_plus/connectivity_plus.dart';
    
    class ConnectivityBanner extends StatelessWidget {
      final Widget child;
      final ConnectivityService service;
    
      const ConnectivityBanner({
        super.key,
        required this.child,
        required this.service,
      });
    
      @override
      Widget build(BuildContext context) {
        return StreamBuilder<List<ConnectivityResult>>(
          stream: service.onStatusChange,
          builder: (context, snapshot) {
            final offline = snapshot.hasData &&
                (snapshot.data!.contains(ConnectivityResult.none) ||
                    snapshot.data!.isEmpty);
            return Column(
              children: [
                AnimatedContainer(
                  duration: const Duration(milliseconds: 300),
                  height: offline ? 32 : 0,
                  width: double.infinity,
                  color: Colors.red.shade700,
                  alignment: Alignment.center,
                  child: offline
                      ? const Text(
                          'Nessuna connessione a Internet',
                          style: TextStyle(color: Colors.white, fontSize: 13),
                        )
                      : null,
                ),
                Expanded(child: child),
              ],
            );
          },
        );
      }
    }

    Risultato atteso

    Quando la rete cade, appare in alto un banner rosso animato; ritorna online lo nasconde.

  5. 5

    Integrare il banner nell'app

    Avvolgiamo il corpo della nostra schermata con ConnectivityBanner. Passiamo un'istanza del servizio creato in precedenza.

    In un'app reale è consigliabile fornire il servizio tramite Provider o get_it, ma per l'esempio lo istanziamo direttamente.

    class HomePage extends StatelessWidget {
      final ConnectivityService _service = ConnectivityService();
    
      HomePage({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('Demo Connettività')),
          body: ConnectivityBanner(
            service: _service,
            child: const Center(
              child: Text('Contenuto principale dell\'app'),
            ),
          ),
        );
      }
    }

    Risultato atteso

    L'app mostra il contenuto principale e reagisce ai cambi di connessione in tempo reale.

  6. 6

    Mostrare un messaggio all'avvio con controllo reale

    All'avvio dell'app potremmo voler verificare subito l'accesso reale a Internet e avvisare l'utente con uno SnackBar. Usiamo il metodo hasInternetAccess creato prima all'interno di initState.

    Ricorda di usare mounted prima di interagire con il context in un contesto asincrono.

    class HomePage extends StatefulWidget {
      const HomePage({super.key});
    
      @override
      State<HomePage> createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      final ConnectivityService _service = ConnectivityService();
    
      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addPostFrameCallback((_) => _checkAtStartup());
      }
    
      Future<void> _checkAtStartup() async {
        final ok = await _service.hasInternetAccess();
        if (!ok && mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Sei offline: alcune funzioni non saranno disponibili')),
          );
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('Demo Connettività')),
          body: ConnectivityBanner(
            service: _service,
            child: const Center(child: Text('Contenuto principale')),
          ),
        );
      }
    }

    Risultato atteso

    All'avvio, se non c'è accesso reale a Internet, compare uno SnackBar informativo.

  7. 7

    Testare su dispositivo ed emulatore

    Per verificare il comportamento:

    • Emulatore Android: attiva/disattiva la modalità aereo o usa i controlli di rete dell'emulatore.
    • Dispositivo fisico: disattiva il Wi‑Fi e i dati mobili.
    • iOS Simulator: simula lo stato offline disattivando la rete del Mac.

    Osserva il banner apparire e scomparire. Prova anche a collegarti a una rete Wi‑Fi senza Internet per verificare che hasInternetAccess restituisca correttamente false.

    Prossimi passi

    • Integra il servizio con Provider o Riverpod per condividerlo in tutta l'app.
    • Metti in coda le richieste fallite per rieseguirle al ritorno online.
    • Combina il banner con un sistema di cache per un vero supporto offline-first.

    Risultato atteso

    Il banner e lo SnackBar reagiscono correttamente ai cambi di stato in tutti gli scenari testati.

CondividiXLinkedInFacebookWhatsApp

Commenti (0)

Ancora nessun commento. Inizia tu!