Localizzare l'utente in Flutter con il pacchetto geolocator
GuideIntermedio35 min Flutter 3.x

Localizzare l'utente in Flutter con il pacchetto geolocator

Molte app moderne hanno bisogno di conoscere la posizione dell'utente: dai servizi di consegna alle app di fitness, dalla ricerca di negozi vicini alle mappe. In questo tutorial impareremo a usare il pacchetto geolocator, la soluzione più diffusa e completa per gestire la geolocalizzazione in Flutter.

Vedremo come richiedere i permessi in modo corretto, ottenere la posizione attuale, ascoltare gli aggiornamenti in tempo reale e calcolare la distanza tra due punti. Il tutto seguendo le best practice per gestire i casi in cui i servizi di localizzazione sono disattivati o i permessi vengono negati.

  1. 1

    Aggiungere la dipendenza e configurare i permessi

    Iniziamo aggiungendo il pacchetto geolocator al progetto. Puoi farlo da terminale con il comando:

    flutter pub add geolocator
    

    Oppure aggiungendo manualmente la dipendenza nel pubspec.yaml. Dopo aver salvato, esegui flutter pub get.

    È fondamentale dichiarare i permessi nelle configurazioni native di ciascuna piattaforma, altrimenti l'app crasherà al momento della richiesta.

    # pubspec.yaml
    dependencies:
      flutter:
        sdk: flutter
      geolocator: ^12.0.0

    Risultato atteso

    Il pacchetto geolocator è installato e disponibile nel progetto.

  2. 2

    Configurare Android e iOS

    Su Android aggiungi i permessi nel file android/app/src/main/AndroidManifest.xml, all'interno del tag <manifest>.

    Su iOS devi aggiungere le chiavi di descrizione nel file ios/Runner/Info.plist: iOS richiede che tu spieghi all'utente perché l'app vuole accedere alla posizione, altrimenti la richiesta verrà rifiutata a livello di sistema.

    <!-- AndroidManifest.xml -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    
    <!-- Info.plist (iOS) -->
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>L'app usa la posizione per mostrarti i luoghi vicini.</string>

    Risultato atteso

    Le piattaforme sono configurate per richiedere l'accesso alla posizione.

  3. 3

    Verificare servizi e richiedere i permessi

    Prima di ottenere la posizione bisogna sempre controllare due cose: che i servizi di localizzazione del dispositivo siano attivi e che l'utente abbia concesso i permessi all'app.

    Creiamo una funzione riutilizzabile che gestisce tutti i casi possibili: servizi disattivati, permesso negato una volta e permesso negato permanentemente. Restituisce true solo quando è tutto a posto.

    import 'package:geolocator/geolocator.dart';
    
    Future<bool> gestisciPermessi() async {
      // 1. Controlla se i servizi di localizzazione sono attivi
      bool serviziAttivi = await Geolocator.isLocationServiceEnabled();
      if (!serviziAttivi) {
        // I servizi GPS sono disattivati dal dispositivo
        return false;
      }
    
      // 2. Controlla lo stato dei permessi
      LocationPermission permesso = await Geolocator.checkPermission();
      if (permesso == LocationPermission.denied) {
        permesso = await Geolocator.requestPermission();
        if (permesso == LocationPermission.denied) {
          return false;
        }
      }
    
      if (permesso == LocationPermission.deniedForever) {
        // L'utente ha negato per sempre: va aperto le impostazioni
        return false;
      }
    
      // Permesso concesso (whileInUse o always)
      return true;
    }

    Risultato atteso

    Una funzione che gestisce in modo sicuro tutti gli scenari di permesso.

  4. 4

    Ottenere la posizione attuale

    Una volta ottenuti i permessi possiamo recuperare la posizione corrente con Geolocator.getCurrentPosition(). Il parametro LocationSettings permette di specificare la precisione desiderata: valori più alti consumano più batteria ma sono più accurati.

    L'oggetto Position restituito contiene latitudine, longitudine, altitudine, velocità e altri dati utili.

    Future<Position?> ottieniPosizione() async {
      final ok = await gestisciPermessi();
      if (!ok) return null;
    
      const settings = LocationSettings(
        accuracy: LocationAccuracy.high,
        distanceFilter: 0,
      );
    
      final posizione = await Geolocator.getCurrentPosition(
        locationSettings: settings,
      );
    
      print('Lat: ${posizione.latitude}, Lng: ${posizione.longitude}');
      return posizione;
    }

    Risultato atteso

    In console vengono stampate le coordinate GPS attuali del dispositivo.

  5. 5

    Mostrare la posizione in un widget

    Integriamo la logica in un widget con stato. Alla pressione di un pulsante recuperiamo la posizione e la mostriamo a schermo, gestendo anche lo stato di caricamento e gli eventuali errori (ad esempio permessi negati).

    class PosizioneScreen extends StatefulWidget {
      const PosizioneScreen({super.key});
    
      @override
      State<PosizioneScreen> createState() => _PosizioneScreenState();
    }
    
    class _PosizioneScreenState extends State<PosizioneScreen> {
      String _testo = 'Nessuna posizione';
      bool _caricamento = false;
    
      Future<void> _aggiorna() async {
        setState(() => _caricamento = true);
        final pos = await ottieniPosizione();
        setState(() {
          _caricamento = false;
          _testo = pos == null
              ? 'Permesso negato o servizi disattivati'
              : 'Lat: ${pos.latitude}\nLng: ${pos.longitude}';
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('La mia posizione')),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(_testo, textAlign: TextAlign.center),
                const SizedBox(height: 20),
                _caricamento
                    ? const CircularProgressIndicator()
                    : ElevatedButton(
                        onPressed: _aggiorna,
                        child: const Text('Rileva posizione'),
                      ),
              ],
            ),
          ),
        );
      }
    }

    Risultato atteso

    Toccando il pulsante l'app mostra le coordinate correnti a schermo.

  6. 6

    Ascoltare gli aggiornamenti in tempo reale

    Per app che seguono lo spostamento dell'utente (fitness, navigazione) possiamo usare lo stream Geolocator.getPositionStream(). Il parametro distanceFilter indica di quanti metri l'utente deve muoversi prima di ricevere un nuovo evento, utile per risparmiare batteria.

    Ricordati sempre di cancellare la sottoscrizione nel dispose() per evitare memory leak.

    import 'dart:async';
    
    StreamSubscription<Position>? _sub;
    
    void avviaTracking() {
      const settings = LocationSettings(
        accuracy: LocationAccuracy.high,
        distanceFilter: 10, // aggiorna ogni 10 metri
      );
    
      _sub = Geolocator.getPositionStream(locationSettings: settings)
          .listen((Position posizione) {
        print('Nuova posizione: ${posizione.latitude}, ${posizione.longitude}');
      });
    }
    
    @override
    void dispose() {
      _sub?.cancel();
      super.dispose();
    }

    Risultato atteso

    L'app riceve aggiornamenti automatici della posizione mentre l'utente si muove.

  7. 7

    Calcolare la distanza tra due punti

    Il pacchetto offre anche Geolocator.distanceBetween(), che calcola la distanza in metri tra due coppie di coordinate usando la formula di Haversine. È perfetto per mostrare, ad esempio, quanto dista un negozio dall'utente.

    Esiste anche bearingBetween() per ottenere la direzione (angolo) tra due punti.

    // Distanza tra il Colosseo e il Duomo di Milano
    double metri = Geolocator.distanceBetween(
      41.8902, 12.4922, // Colosseo (Roma)
      45.4642, 9.1900,  // Duomo (Milano)
    );
    
    final km = (metri / 1000).toStringAsFixed(1);
    print('Distanza: $km km'); // circa 480.9 km

    Risultato atteso

    Viene stampata la distanza in chilometri tra i due punti geografici.

CondividiXLinkedInFacebookWhatsApp

Commenti (0)

Ancora nessun commento. Inizia tu!