Scansionare codici QR e a barre in Flutter con mobile_scanner
GuideIntermedio35 min Flutter 3.x

Scansionare codici QR e a barre in Flutter con mobile_scanner

La scansione di codici QR e a barre è una funzionalità richiesta in moltissime app moderne: dalla lettura di biglietti agli inventari, dai pagamenti alle promozioni. In questo tutorial useremo il pacchetto mobile_scanner, una soluzione performante basata su ML Kit (Android) e AVFoundation (iOS), che offre un'API semplice e reattiva.

Al termine avrai un'app funzionante in grado di rilevare codici in tempo reale, mostrare il risultato e gestire funzionalità come il flash e il cambio di fotocamera.

  1. 1

    Aggiungere la dipendenza mobile_scanner

    Aggiungi il pacchetto mobile_scanner al tuo progetto. Puoi farlo da terminale oppure modificando direttamente il file pubspec.yaml.

    Da terminale esegui:

    flutter pub add mobile_scanner
    

    In alternativa, aggiungi manualmente la dipendenza e lancia flutter pub get.

    dependencies:
      flutter:
        sdk: flutter
      mobile_scanner: ^5.2.3

    Risultato atteso

    Il pacchetto mobile_scanner viene scaricato e reso disponibile nel progetto.

  2. 2

    Configurare i permessi della fotocamera

    La scansione richiede l'accesso alla fotocamera. Devi dichiarare i permessi sia su Android sia su iOS.

    Android — nel file android/app/src/main/AndroidManifest.xml, all'interno del tag <manifest>, aggiungi il permesso. Assicurati inoltre che minSdkVersion sia almeno 21 in android/app/build.gradle.

    iOS — nel file ios/Runner/Info.plist aggiungi la chiave con una descrizione dell'uso della fotocamera.

    <!-- AndroidManifest.xml -->
    <uses-permission android:name="android.permission.CAMERA" />
    
    <!-- ios/Runner/Info.plist -->
    <key>NSCameraUsageDescription</key>
    <string>L'app usa la fotocamera per scansionare i codici QR e a barre.</string>

    Risultato atteso

    Al primo avvio della scansione il sistema chiederà all'utente il permesso di accedere alla fotocamera.

  3. 3

    Creare la schermata dello scanner

    Creiamo un widget StatefulWidget che ospita il MobileScanner. Il widget mostra il flusso della fotocamera a schermo intero e utilizza il callback onDetect per ricevere i codici rilevati.

    Usiamo un MobileScannerController per poter controllare in seguito il flash e la fotocamera, e ricordiamo di rilasciarlo nel metodo dispose.

    import 'package:flutter/material.dart';
    import 'package:mobile_scanner/mobile_scanner.dart';
    
    class ScannerScreen extends StatefulWidget {
      const ScannerScreen({super.key});
    
      @override
      State<ScannerScreen> createState() => _ScannerScreenState();
    }
    
    class _ScannerScreenState extends State<ScannerScreen> {
      final MobileScannerController _controller = MobileScannerController();
      String? _lastCode;
    
      @override
      void dispose() {
        _controller.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('Scanner')),
          body: MobileScanner(
            controller: _controller,
            onDetect: (capture) {
              final List<Barcode> barcodes = capture.barcodes;
              if (barcodes.isNotEmpty) {
                final code = barcodes.first.rawValue;
                if (code != null && code != _lastCode) {
                  setState(() => _lastCode = code);
                }
              }
            },
          ),
        );
      }
    }

    Risultato atteso

    Avviando l'app viene mostrata l'anteprima della fotocamera e i codici inquadrati vengono rilevati automaticamente.

  4. 4

    Mostrare il risultato della scansione

    Rendiamo più utile lo scanner mostrando il valore rilevato in fondo allo schermo. Usiamo uno Stack per sovrapporre un pannello di risultato all'anteprima della fotocamera.

    Una buona pratica è evitare letture ripetute dello stesso codice: nel passo precedente lo gestivamo confrontando con _lastCode.

    body: Stack(
      children: [
        MobileScanner(
          controller: _controller,
          onDetect: (capture) {
            final barcodes = capture.barcodes;
            if (barcodes.isNotEmpty) {
              final code = barcodes.first.rawValue;
              if (code != null && code != _lastCode) {
                setState(() => _lastCode = code);
              }
            }
          },
        ),
        Align(
          alignment: Alignment.bottomCenter,
          child: Container(
            width: double.infinity,
            color: Colors.black54,
            padding: const EdgeInsets.all(16),
            child: Text(
              _lastCode ?? 'Inquadra un codice...',
              style: const TextStyle(color: Colors.white, fontSize: 16),
              textAlign: TextAlign.center,
            ),
          ),
        ),
      ],
    ),

    Risultato atteso

    In basso appare un pannello che mostra il contenuto dell'ultimo codice scansionato.

  5. 5

    Controllare flash e fotocamera

    Il MobileScannerController permette di attivare la torcia (toggleTorch) e cambiare tra fotocamera anteriore e posteriore (switchCamera). Aggiungiamo due pulsanti nell'AppBar.

    Da mobile_scanner 5.x puoi anche usare il ValueListenableBuilder sul controller per aggiornare l'icona in base allo stato della torcia.

    appBar: AppBar(
      title: const Text('Scanner'),
      actions: [
        IconButton(
          icon: const Icon(Icons.flash_on),
          onPressed: () => _controller.toggleTorch(),
        ),
        IconButton(
          icon: const Icon(Icons.cameraswitch),
          onPressed: () => _controller.switchCamera(),
        ),
      ],
    ),

    Risultato atteso

    I due pulsanti nell'AppBar consentono di accendere il flash e passare da una fotocamera all'altra.

  6. 6

    Filtrare i tipi di codice e restituire il risultato

    Puoi limitare la scansione a determinati formati (ad esempio solo QR code) passando i formats al controller. Inoltre, quando un codice valido viene rilevato, spesso vogliamo chiudere la schermata e restituire il valore alla pagina chiamante.

    Esegui Navigator.pop all'interno del callback, mettendo in pausa il controller per evitare doppie letture.

    final MobileScannerController _controller = MobileScannerController(
      formats: [BarcodeFormat.qrCode],
    );
    
    // Nel callback onDetect:
    onDetect: (capture) {
      final code = capture.barcodes.first.rawValue;
      if (code != null) {
        _controller.stop();
        Navigator.of(context).pop(code);
      }
    },
    
    // Nella pagina chiamante:
    ElevatedButton(
      onPressed: () async {
        final result = await Navigator.push<String>(
          context,
          MaterialPageRoute(builder: (_) => const ScannerScreen()),
        );
        if (result != null) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Codice: $result')),
          );
        }
      },
      child: const Text('Scansiona QR'),
    ),

    Risultato atteso

    Lo scanner riconosce solo i QR code, si chiude alla prima lettura valida e restituisce il valore alla schermata precedente che lo mostra in una SnackBar.

CondividiXLinkedInFacebookWhatsApp

Commenti (0)

Ancora nessun commento. Inizia tu!