Detectar conexión a Internet en Flutter

Video thumbnail

Verificar si una app Flutter tiene conexión a internet parece algo sencillo… hasta que empiezas a integrar navegación, ciclo de vida de widgets y actualizaciones de UI. Yo he pasado por ese dolor varias veces, y aquí te voy a contar exactamente cómo lo resuelvo en mis proyectos usando connectivity_plus, un CustomScaffold reutilizable y un flujo que no rompe la experiencia del usuario.

¿Por qué es importante verificar la conexión a internet en Flutter?

Una gran parte de las apps modernas dependen de internet: listas de publicaciones, autenticación, imágenes, feeds, etc. Si la app intenta construir una interfaz que necesita datos sin tener internet, no solo fallará la carga: también puede romperse el flujo de navegación o presentar pantallas incompletas.

En mi caso, suelo trabajar con aplicaciones donde cada página necesita hacer una petición. Por eso siempre prefiero validar la conexión antes de construir la UI. Y no, Flutter no trae una forma nativa de “detener el build hasta saber si hay internet”, así que toca hacerlo de forma inteligente.

Opciones disponibles para detectar conectividad en Flutter

Antes de mostrarte mi enfoque, vale la pena revisar qué alternativas existen.

Comparación rápida: connectivity_plus vs internet_connection_checker

connectivity_plus:

  • Detecta si estás conectado a algún tipo de red (WiFi, móvil, ethernet).
  • No garantiza que haya internet real, solo que existe una conexión de red.
  • Muy útil para flujos iniciales e integración con el ciclo de vida del widget.

internet_connection_checker:

  • Comprueba si realmente puedes “salir” a internet.
  • Hace pings a servidores para validar la salida real.
  • Útil cuando necesitas certeza absoluta de conectividad.

Cuándo usar cada paquete

Yo uso connectivity_plus cuando necesito saber rápido si hay red para mostrar o bloquear pantallas. En cambio, uso internet_connection_checker cuando necesito confirmar conectividad real antes de consumir un API.

En este artículo nos enfocamos en connectivity_plus, porque es ideal para controlar pantallas completas como “sin conexión”.

Cómo verificar la conexión a internet con connectivity_plus

Te voy a mostrar cómo puedes verificar la conexión a internet en una aplicación en Flutter para eso estoy empleando el siguiente paquete:

import 'package:connectivity_plus/connectivity_plus.dart';

Se instala mediante:

$ flutter pub add connectivity_plus

Aquí puedes ver la compatibilidad que tiene. Es un proceso bastante similar al de siempre: abres el pubspec.yaml, vienes a la parte de instalación, copias el nombre del paquete y colocas la versión si quieres; si no, simplemente no la colocas.

Una vez instalado, lo importas en donde quieras hacer la verificación. En mi caso, estoy empleando un Scaffold personalizado que es el que llamo CustomScaffold.

Uso del CustomScaffold

Este widget lo utilizo para colocarlo en todas mis páginas, es decir, en todas las pantallas que tengo para mi aplicación (todas las que puedes ver por acá). Todas las páginas que tengo rotadas a nivel de la aplicación utilizan este CustomScaffold.

Además de poder, por ejemplo, personalizar dónde quiero colocar el drawer y demás, también es útil para este tipo de situaciones en las cuales queremos hacer alguna comprobación previa antes de cargar cada página, como en este caso sería la verificación de conexión a internet.

Aunque ya esa implementación depende un poco del lugar donde tú la quieras colocar, el punto es que, al final, esto no es más que un widget como cualquier otro: un StatefulWidget.

Detectar conectividad en initState sin romper el ciclo de vida

Cuando empecé a implementar esto, una de las primeras cosas que descubrí es que no es buena idea poner async directamente en initState(), aunque Flutter te deje hacerlo. He visto comportamientos raros en el montaje del widget y prefiero evitarlo.

Así que lo que hago es invocar un método separado, que sí es async, desde initState():

@override
void initState() {
 init();
 super.initState();
}

Esto mantiene limpio el ciclo de vida y deja el trabajo pesado fuera.

Crear un método asíncrono seguro para validar internet

Mi método suele verse así:

Future<bool> checkIsInternetConnection() async {
 var connectivityResult = await Connectivity().checkConnectivity();
 return connectivityResult != ConnectivityResult.none;
}

El funcionamiento es sencillo:

  • Se define un booleano, que por defecto es true. Esto indica que, inicialmente, asumimos que hay conexión a Internet, lo cual es lo más seguro.
  • Luego, se verifica la conexión mediante un método async (await), como puedes ver.

El resultado de este método puede devolver varias cosas, pero para nuestros fines prácticos solo nos interesa si no hay conexión.

  • Si no hay conexión, el método devuelve un objeto ConnectivityResult.none.
  • En caso de que sí haya conexión, también podríamos identificar si es Ethernet, móvil o WiFi, pero nuevamente, para este ejemplo, lo importante es detectar cuando no tenemos conexión.

Aquí verificamos si el valor es igual a cierto estado.

  • Si se cumple la condición, significa que no tenemos conexión a Internet.
  • En ese caso, el método devolvería false, indicando la ausencia de conexión.
  • Con este resultado, podemos ejecutar la acción que corresponda cuando no hay Internet disponible.

Verificación de conexión a Internet

Entonces, esto no lo verifico directamente aquí por ahora; más adelante te voy a indicar por qué.

Recuerda que la problemática principal es que este proceso es complicado de manejar de manera asíncrona, porque aunque Flutter lo acepte, pueden surgir varios problemas.

Por eso, lo que hice fue mover la parte asíncrona a otro método. Aquí simplemente la invoco, y fíjate que no estoy bloqueando el hilo principal. Más adelante veremos cómo manejar esto correctamente.

Método asíncrono de verificación

Aquí tenemos el método asíncrono que estamos invocando. Este método se puede utilizar para cualquier inicialización, pero en este caso solo necesitamos verificar la conexión a Internet.

En mi flujo, si _thereIsInternet es falso, entonces en el build() devuelvo una pantalla completa que dice básicamente “no hay internet” y ofrece un botón para reintentar.

Algo así:

if (!_thereIsInternet) {
 return Scaffold(
   appBar: AppBar(title: Text(widget.title)),
   body: Column(
     mainAxisAlignment: MainAxisAlignment.center,
     children: [
       Text('No hay conexión a internet'),
       SizedBox(height: 15),
       MaterialButton(
         color: Theme.of(context).primaryColor,
         onPressed: () async {
           await init();
           if (_thereIsInternet) {
             Navigator.pushReplacement(
               context,
               MaterialPageRoute(builder: (_) => ListPage(...)),
             );
           }
         },
         child: Text('Reintentar', style: TextStyle(color: Colors.white)),
       )
     ],
   ),
 );
}

Finalmente, verificamos la respuesta y actuamos en consecuencia.

ConnectivityResult

Por alguna razón, lo implementé al revés. Perfectamente podría hacerse de la forma tradicional, pero en este caso lo dejé así.

return  connectivityResult != ConnectivityResult.none

Como puedes suponer, y tal como se ve en el código, esto es una petición de tipo asíncrono. Todas las conexiones que involucran disco o Internet son asíncronas, por razones obvias.

Si hay conexión, se construye el widget normal.

  • Si no hay conexión, podemos mostrar otro tipo de widget, como un mensaje de error o un indicador de falta de red.

Ejemplo completo integrándolo en un Scaffold reutilizable

Aquí es donde realmente saco provecho del patrón.

Cómo funciona un CustomScaffold para validar internet en cada página

Yo tengo un widget que uso en todas las páginas: un CustomScaffold.
Lo creé porque necesitaba un punto común para:

  • personalizar appbars,
  • manejar drawers,
  • y validar la conexión antes de construir la pantalla real.

Es perfecto porque todas mis páginas pasan por ahí, así que la verificación funciona automáticamente.

@override
 Widget build(BuildContext context) {
   if (!_thereIsInternet) {
     // no hay conexion
     return Scaffold(
       appBar: AppBar(
         title: Text(widget.title),
       ),
       body: SizedBox(
         width: double.infinity,
         child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
           crossAxisAlignment: CrossAxisAlignment.center,
           children: [
             Text(LocaleKeys.thereIsNoInternet.tr()),
             const SizedBox(height: 15),
             MaterialButton(
               color: Theme.of(context).primaryColor,
               textTheme: Theme.of(context).buttonTheme.textTheme,
               // textTheme: Theme.of(context).buttonTheme,
               onPressed: () async {
                 await init();
                 if (_thereIsInternet) {
                   // navega a alguna pagina para regargar
                   Navigator.pushReplacement(
                       context,
                       MaterialPageRoute(
                           builder: (context) => ListPage(
                               false, 0, 0, '', LocaleKeys.lastsPosts.tr())));
                   // setState(() {});
                   // no llama al metodo de build
                   // Navigator.pushReplacement(
                   //     context,
                   //     MaterialPageRoute(
                   //         builder: (BuildContext context) => super.widget));
                 }
               },
               child: Text(LocaleKeys.reload.tr(),
                   style: Theme.of(context)
                       .textTheme
                       .bodyLarge!
                       .copyWith(color: Colors.white)),
             ),
           ],
         ),
       ),
     );
   }

En este caso, utilizo un botón en el medio que indica que no hay Internet, que es el mensaje que estoy mostrando actualmente.

Cuando el usuario desea verificar la conexión, lo que hago es colocar un botón que llama al método de verificación que te mostré antes.

Si la verificación determina que thereIsInternet es true, es decir, que hay conexión a Internet, entonces puedo:

  • Mostrar contenido adicional.
  • Navegar hacia una página específica, en este caso, el listado de publicaciones.

Este botón siempre estará presente, y cada vez que el usuario lo pulse, se ejecuta la verificación de conexión. Si la conexión es exitosa (true), la aplicación navega correctamente a la otra página.

A efectos del usuario, esto hace que parezca que la aplicación se está cargando. Idealmente, sería mejor recargar la página actual, pero hasta donde he investigado, no hay un método oficial en Flutter para hacer un "hard reload" de la página.

Para evitar esta limitación, utilizo pushReplacement para navegar hacia otra página, reemplazando la actual.

Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => ListPage( false, 0, 0, '', LocaleKeys.lastsPosts.tr())));

Por lo tanto, reemplazamos esta página y nos evitamos toda la complejidad relacionada con la navegación y la verificación de Internet.

Poco más que decir: es así de simple. Con estas líneas de código, puedes verificar fácilmente cuándo hay conexión o no y, a partir de ahí, actuar en consecuencia.

  • Si no hay conexión, puedes mostrar una interfaz diferente.
  • En este caso, por ejemplo, si es la página de listado de publicaciones, no se construirá nada porque no hay conexión.
  • Una vez que tengamos conexión, simplemente navegamos a una página específica.

Mostrar una pantalla sin conexión

El CustomScaffold verifica la conexión en initState, y si no hay internet:

  • No muestra el contenido real de la página.
  • Muestra la pantalla “sin conexión”.
  • Espera a que el usuario pulse Reintentar.

Recargar y navegar cuando vuelve el internet (pushReplacement)

Flutter no trae un “hard reload” de páginas.
Yo mismo investigué esto bastante y no encontré una forma oficial de recargar toda la página “desde dentro”.

Así que uso esta técnica:

Navigator.pushReplacement(
 context,
 MaterialPageRoute(builder: (context) => ListPage(...)),
);

Esto reconstruye la navegación desde esa página y te quita un montón de dolores de cabeza.

Buenas prácticas para manejar el modo offline en apps Flutter

Patrones de UX recomendados

  • No bloquees al usuario sin explicación.
  • Siempre ofrece un botón claro de “Reintentar”.
  • Evita pantallas vacías, loaders infinitos o errores planos.
  • Permite navegar a secciones que no necesitan internet.
  • Da feedback inmediato al tocar el botón de reintento.

Errores comunes al usar async/await en widgets

  • Poner async directamente en initState.
  • Cambiar variables de estado sin llamar a setState después.
  • Navegar desde build() (esto rompe animaciones).
  • Crear listeners sin cancelarlos.
  • Asumir que “hay red = hay internet”.

Preguntas frecuentes sobre la conectividad en Flutter

  • ¿connectivity_plus comprueba internet real?
    • No. Solo detecta si tienes red.
  • ¿Cómo compruebo internet real?
    • Con internet_connection_checker.
  • ¿Se puede recargar una página completa en Flutter?
    • No nativamente. Lo más cercano es usar pushReplacement.
  • ¿Es obligatorio usar un Scaffold personalizado?
    • No, pero ayuda mucho si necesitas lógica repetida.

Conclusión

Comprobar la conexión a internet en Flutter no es complicado, pero hacerlo bien —sin bloquear el ciclo de vida, sin romper la UI y sin llenar el código de hacks— requiere un enfoque ordenado.

La combinación que uso en mis proyectos:

  • ✔️ connectivity_plus
  • ✔️ un método async seguro
  • ✔️ un CustomScaffold que centraliza la verificación
  • ✔️ pantallas offline limpias
  • ✔️ pushReplacement para reconstruir navegación

Acepto recibir anuncios de interes sobre este Blog.

Veremos como podemos detectar conexión a Internet en una aplicación en Flutter mediante un paquete.

| 👤 Andrés Cruz

🇺🇸 In english