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.
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 a 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 a 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- Administrador de estados (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);
}
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);
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();
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.