Connectivity plus. Muestra a tus usuarios si tienen conexión a internet

Tienes una aplicación y te gustaría mostrar a los usuarios una advertencia cuando el dispositivo pierde conexión a internet como en la siguiente imagen:

Bueno, es mucho más fácil de lo que parece, pero antes de comenzar puedes descargar el código fuente de Github o puedes ver el videotutorial en YouTube.

Importante

En este artículo utilizaremos ValueNotifier para mostrar a los usuarios si no hay conexión. Ejemplos con Cubit, GetX y Provider están disponibles en el videotutorial de YouTube.

Requisitos

Connectivity Plus: Es un paquete que nos dice cuando hay un cambio en la red. Por ejemplo cuando te conectas o desconectas a una red utilizando wifi. Es importante recordar que este paquete por sí solo no nos dice si hay o no conexión a internet. RxDart: Nos va ayudar a emitir estados anteriores del estado de la conexión.

Para saber si hay o no conexión a internet vamos a utilizar la solución que pueden encontrar en stackoverflow.

1- Agregar dependencias

En el archivo pubspec.yaml agregamos los siguientes paquetes:

dependencies:  
  flutter:  
    sdk: flutter  
 
  rxdart: ^0.27.3  
  connectivity_plus: ^2.3.0

2- Verificar conexión a internet.

Creamos un enum para saber el estado de la conexión actual.

enum ConnectionStatus {  
  online,  
  offline,  
}

Creamos una clase que nos va ayudar a verificar el estado de la conexión y emitir nuevos estados si esta cambia.

class CheckInternetConnection {
  final Connectivity _connectivity = Connectivity();

  // El estado por defecto sera Online. Este controlador nos va
  // ayudar a emitir nuevos estados cuando la conexion cambie.
  final _controller = BehaviorSubject.seeded(ConnectionStatus.online);
  StreamSubscription? _connectionSubscription;

  CheckInternetConnection() {
    _checkInternetConnection();
  }

  // La clase [ConnectionStatusValueNotifier] va suscribirse a este Stream
  // y cuando la conexión cambie el status se va actualizar
  Stream<ConnectionStatus> internetStatus() {
    _connectionSubscription ??= _connectivity.onConnectivityChanged
        .listen((_) => _checkInternetConnection());
    return _controller.stream;
  }

  // Solución de stackoverflow
  Future<void> _checkInternetConnection() async {
    try {
      // Algunas veces, después de conectarnos a la red, esta función
      // se ejecuta cuando el dispositivo todavía no establece
      // conexión a internet. Este delay de 3 segundos le da tiempo
      // al dispositivo a conectarse y evitar falsos negativos. 
      await Future.delayed(const Duration(seconds: 3));
      final result = await InternetAddress.lookup('google.com');
      if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
        _controller.sink.add(ConnectionStatus.online);
      } else {
        _controller.sink.add(ConnectionStatus.offline);
      }
    } on SocketException catch (_) {
      _controller.sink.add(ConnectionStatus.offline);
    }
  }

  Future<void> close() async {
  	// Cancelamos la suscripción y cerramos el controlador
    await _connectionSubscription?.cancel();
    await _controller.close();
  }
}

Esta clase se debe inicializar solo una vez durante todo el ciclo de vida de la app. Para este ejemplo yo la voy a inicializar de forma global en el archivo main.dart:

// Inicializar solo una vez.   
final internetChecker = CheckInternetConnection();  
  
void main() async {  
  runApp(  
    MyApp(),  
  );  
}

3- Manejador de estado (State management)

Para mantener el estado vamos a utilizar ValueNotifier así que creamos la siguiente clase:

class ConnectionStatusValueNotifier extends ValueNotifier<ConnectionStatus> {
  // Nos ayuda a mantener una suscripción con la 
  // clase [CheckInternetConnection]
  late StreamSubscription _connectionSubscription;  
  
  ConnectionStatusValueNotifier() : super(ConnectionStatus.online) {
    // Cada vez que se emite un nuevos estado actualizamos [value]
    // esto va hacer que nuestro widget se vuelva a construir.
    _connectionSubscription = internetChecker  
        .internetStatus()  
        .listen((newStatus) => value = newStatus);  
  }  
  
  @override  
  void dispose() {  
	  // Cancelamos la subscription
	 _connectionSubscription.cancel();  
	 super.dispose();  
  }  
}

4- Widget para mostrar que no hay conexión

Creamos el widget que utilizará ValueListenableBuilder para escuchar los valores emitidos por la clase ConnectionStatusValueNotifier

class WarningWidgetValueNotifier extends StatelessWidget {
  const WarningWidgetValueNotifier({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: ConnectionStatusValueNotifier(),
      builder: (context, ConnectionStatus status, child) {
        return Visibility(
          visible: status != ConnectionStatus.online,
          child: Container(
            padding: const EdgeInsets.all(16),
            height: 60,
            color: Colors.brown,
            child: Row(
              children: [
                const Icon(Icons.wifi_off),
                const SizedBox(width: 8),
                const Text('No internet connection.'),
              ],
            ),
          ),
        );
      },
    );
  }
}

5- Mostrar cuando no hay conexión

Ahora solo tenemos que agregar este widget en cualquier pantalla donde queremos que se muestre la advertencia. Por ejemplo:

class MyApp extends StatelessWidget {
  const MyApp();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Value notifier Example'),
      ),
      body: Column(
        children: <Widget>[
          const WarningWidgetValueNotifier(),
          const Text('Abigail'),
          const Text('Alexandra'),
          const Text('Amelia'),
        ],
      ),
    );
  }
}

Conclusión

Mostrar a tus usuarios que no tienen conexión a internet es mucho más fácil de lo que parece y no es necesario agregar ningún paquete para manejar estados.

Videotutorial en YouTube

Si quieres ver el resultado final puedes ver el video tutorial de este artículo en YouTube:

Comparte este artículo