dart flutter

dart - Compruebe si hay una conexión a Internet disponible en la aplicación Flutter



(7)

Tengo una llamada de red para ser ejecutada. Pero antes de hacerlo, necesito verificar si el dispositivo tiene conectividad a Internet.

Esto es lo que he hecho hasta ahora:

var connectivityResult = new Connectivity().checkConnectivity();// User defined class if (connectivityResult == ConnectivityResult.mobile || connectivityResult == ConnectivityResult.wifi) {*/ this.getData(); } else { neverSatisfied(); }

El método anterior no funciona.


El complemento de connectivity indica en sus documentos que solo proporciona información si hay una conexión de red, pero no si la red está conectada a Internet

Tenga en cuenta que en Android, esto no garantiza la conexión a Internet. Por ejemplo, la aplicación podría tener acceso wifi pero podría ser una VPN o un WiFi del hotel sin acceso.

Puedes usar

import ''dart:io''; ... try { final result = await InternetAddress.lookup(''google.com''); if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { print(''connected''); } } on SocketException catch (_) { print(''not connected''); }


He creado un paquete que (creo) trata de manera confiable este problema.

El paquete en pub.dev

El paquete en GitHub

La discusión es muy bienvenida. Puede usar el rastreador de problemas en GitHub.

Ya no creo que esto a continuación sea un método confiable:

Quiero agregar algo a respuesta de : realmente debería agregar una captura más, que capturará todas las demás excepciones (solo para estar seguro), O simplemente elimine el tipo de excepción por completo y use una captura, que se ocupa de todas las excepciones:

Caso 1:

try { await Firestore.instance .runTransaction((Transaction tx) {}) .timeout(Duration(seconds: 5)); hasConnection = true; } on PlatformException catch(_) { // May be thrown on Airplane mode hasConnection = false; } on TimeoutException catch(_) { hasConnection = false; } catch (_) { hasConnection = false; }

o incluso más simple ...

Caso 2:

try { await Firestore.instance .runTransaction((Transaction tx) {}) .timeout(Duration(seconds: 5)); hasConnection = true; } catch (_) { hasConnection = false; }


Hice una clase base para el estado del widget

Uso en lugar de State<LoginPage> use BaseState<LoginPage> luego use la variable booleana isOnline

dependencies: connectivity: ^0.4.3+2

Primero, agregue el complemento de conectividad:

import ''dart:async''; import ''dart:io''; import ''package:flutter/services.dart''; import ''package:connectivity/connectivity.dart''; import ''package:flutter/widgets.dart''; /// a base class for any statful widget for checking internet connectivity abstract class BaseState<T extends StatefulWidget> extends State { final Connectivity _connectivity = Connectivity(); StreamSubscription<ConnectivityResult> _connectivitySubscription; /// the internet connectivity status bool isOnline = true; /// initialize connectivity checking /// Platform messages are asynchronous, so we initialize in an async method. Future<void> initConnectivity() async { // Platform messages may fail, so we use a try/catch PlatformException. try { await _connectivity.checkConnectivity(); } on PlatformException catch (e) { print(e.toString()); } // If the widget was removed from the tree while the asynchronous platform // message was in flight, we want to discard the reply rather than calling // setState to update our non-existent appearance. if (!mounted) { return; } await _updateConnectionStatus().then((bool isConnected) => setState(() { isOnline = isConnected; })); } @override void initState() { super.initState(); initConnectivity(); _connectivitySubscription = Connectivity() .onConnectivityChanged .listen((ConnectivityResult result) async { await _updateConnectionStatus().then((bool isConnected) => setState(() { isOnline = isConnected; })); }); } @override void dispose() { _connectivitySubscription.cancel(); super.dispose(); } Future<bool> _updateConnectionStatus() async { bool isConnected; try { final List<InternetAddress> result = await InternetAddress.lookup(''google.com''); if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { isConnected = true; } } on SocketException catch (_) { isConnected = false; return false; } return isConnected; } }

Luego agregue la clase BaseState

try { await Firestore.instance.runTransaction((Transaction tx) {}).timeout(Duration(seconds: 5)); hasConnection = true; } on PlatformException catch(_) { // May be thrown on Airplane mode hasConnection = false; } on TimeoutException catch(_) { hasConnection = false; }


Para cualquier otra persona que aterrice aquí, me gustaría agregar a la respuesta de Günter Zöchbauer, esta fue mi solución para implementar una utilidad para saber si hay Internet o no, independientemente de cualquier otra cosa.

Renuncia:

Soy nuevo en Dart y Flutter, por lo que este puede no ser el mejor enfoque, pero me encantaría recibir comentarios.

Combinando flutter_connectivity y la prueba de conexión de Günter Zöchbauer

Mis requisitos

No quería tener un montón de código repetido en cualquier lugar donde necesitaba verificar la conexión y quería que actualizara automáticamente los componentes o cualquier otra cosa que se preocupara por la conexión cada vez que había un cambio.

ConnectionStatusSingleton

Primero configuramos un Singleton. Si no está familiarizado con este patrón, hay mucha buena información en línea sobre ellos. Pero lo esencial es que desea crear una sola instancia de una clase durante el ciclo de vida de la aplicación y poder usarla en cualquier lugar.

Este singleton se conecta a flutter_connectivity y escucha los cambios de conectividad, luego prueba la conexión de red, luego usa un StreamController para actualizar cualquier cosa que le StreamController .

Se parece a esto:

import ''dart:io''; //InternetAddress utility import ''dart:async''; //For StreamController/Stream import ''package:connectivity/connectivity.dart''; class ConnectionStatusSingleton { //This creates the single instance by calling the `_internal` constructor specified below static final ConnectionStatusSingleton _singleton = new ConnectionStatusSingleton._internal(); ConnectionStatusSingleton._internal(); //This is what''s used to retrieve the instance through the app static ConnectionStatusSingleton getInstance() => _singleton; //This tracks the current connection status bool hasConnection = false; //This is how we''ll allow subscribing to connection changes StreamController connectionChangeController = new StreamController.broadcast(); //flutter_connectivity final Connectivity _connectivity = Connectivity(); //Hook into flutter_connectivity''s Stream to listen for changes //And check the connection status out of the gate void initialize() { _connectivity.onConnectivityChanged.listen(_connectionChange); checkConnection(); } Stream get connectionChange => connectionChangeController.stream; //A clean up method to close our StreamController // Because this is meant to exist through the entire application life cycle this isn''t // really an issue void dispose() { connectionChangeController.close(); } //flutter_connectivity''s listener void _connectionChange(ConnectivityResult result) { checkConnection(); } //The test to actually see if there is a connection Future<bool> checkConnection() async { bool previousConnection = hasConnection; try { final result = await InternetAddress.lookup(''google.com''); if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { hasConnection = true; } else { hasConnection = false; } } on SocketException catch(_) { hasConnection = false; } //The connection status changed send out an update to all listeners if (previousConnection != hasConnection) { connectionChangeController.add(hasConnection); } return hasConnection; } }

Uso

Inicialización

Primero tenemos que asegurarnos de llamar a la inicialización de nuestro singleton. Pero solo una vez. Esto depende de ti, pero lo hice en main() mi aplicación:

void main() { ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance(); connectionStatus.initialize(); runApp(MyApp()); //Call this if initialization is occuring in a scope that will end during app lifecycle //connectionStatus.dispose(); }

En Widget o en otro lugar

import ''dart:async''; //For StreamSubscription ... class MyWidgetState extends State<MyWidget> { StreamSubscription _connectionChangeStream; bool isOffline = false; @override initState() { super.initState(); ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance(); _connectionChangeStream = connectionStatus.connectionChange.listen(connectionChanged); } void connectionChanged(dynamic hasConnection) { setState(() { isOffline = !hasConnection; }); } @override Widget build(BuildContext ctxt) { ... } }

¡Espero que alguien más encuentre esto útil!

Ejemplo de repositorio de github: https://github.com/dennmat/flutter-connectiontest-example

Cambia el modo avión en el emulador para ver el resultado


Siguiendo la share @dennmatt, noté que InternetAddress.lookup puede devolver resultados exitosos incluso si la conexión a Internet está apagada. Lo probé conectándome desde mi simulador al WiFi de mi casa y luego desconectando el cable de mi enrutador. Creo que la razón es que el enrutador almacena en caché los resultados de búsqueda de dominio, por lo que no tiene que consultar los servidores DNS en cada solicitud de búsqueda.

De todos modos, si usa Firestore como yo, puede reemplazar el bloque try-SocketException-catch con una transacción vacía y capturar TimeoutExceptions:

Text(isOnline ? ''is Online'' : ''is Offline'')

Además, tenga en cuenta que previousConnection se establece antes de la comprobación de intenet asíncrona, por lo que teóricamente si checkConnection() se llama varias veces en poco tiempo, podría haber múltiples hasConnection=true en una fila o múltiples hasConnection=false en una fila. No estoy seguro de si @dennmatt lo hizo a propósito o no, pero en nuestro caso de uso no hubo efectos secundarios ( setState solo se llamó dos veces con el mismo valor).


Utilizando

dependencies: connectivity: ^0.4.2

lo que obtuvimos de los connectivity es

import ''package:connectivity/connectivity.dart''; Future<bool> check() async { var connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult == ConnectivityResult.mobile) { return true; } else if (connectivityResult == ConnectivityResult.wifi) { return true; } return false; }

El futuro es poco problemático para mí, tenemos que implementarlo cada vez como:

check().then((intenet) { if (intenet != null && intenet) { // Internet Present Case } // No-Internet Case });

Entonces, para resolver este problema, he creado una clase que acepta una función con un parámetro boolean isNetworkPresent como este

methodName(bool isNetworkPresent){}

Y la clase de utilidad es

import ''package:connectivity/connectivity.dart''; class NetworkCheck { Future<bool> check() async { var connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult == ConnectivityResult.mobile) { return true; } else if (connectivityResult == ConnectivityResult.wifi) { return true; } return false; } dynamic checkInternet(Function func) { check().then((intenet) { if (intenet != null && intenet) { func(true); } else{ func(false); } }); } }

Y para utilizar la utilidad de verificación de conectividad

fetchPrefrence(bool isNetworkPresent) { if(isNetworkPresent){ }else{ } }

usaré esta sintaxis

NetworkCheck networkCheck = new NetworkCheck(); networkCheck.checkInternet(fetchPrefrence)


Ejemplo completo que demuestra un oyente de la conectividad a internet y su fuente.

Crédito a: connectivity y Günter Zöchbauer

import ''dart:async''; import ''dart:io''; import ''package:connectivity/connectivity.dart''; import ''package:flutter/material.dart''; void main() => runApp(MaterialApp(home: HomePage())); class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { Map _source = {ConnectivityResult.none: false}; MyConnectivity _connectivity = MyConnectivity.instance; @override void initState() { super.initState(); _connectivity.initialise(); _connectivity.myStream.listen((source) { setState(() => _source = source); }); } @override Widget build(BuildContext context) { String string; switch (_source.keys.toList()[0]) { case ConnectivityResult.none: string = "Offline"; break; case ConnectivityResult.mobile: string = "Mobile: Online"; break; case ConnectivityResult.wifi: string = "WiFi: Online"; } return Scaffold( appBar: AppBar(title: Text("Internet")), body: Center(child: Text("$string", style: TextStyle(fontSize: 36))), ); } @override void dispose() { _connectivity.disposeStream(); super.dispose(); } } class MyConnectivity { MyConnectivity._internal(); static final MyConnectivity _instance = MyConnectivity._internal(); static MyConnectivity get instance => _instance; Connectivity connectivity = Connectivity(); StreamController controller = StreamController.broadcast(); Stream get myStream => controller.stream; void initialise() async { ConnectivityResult result = await connectivity.checkConnectivity(); _checkStatus(result); connectivity.onConnectivityChanged.listen((result) { _checkStatus(result); }); } void _checkStatus(ConnectivityResult result) async { bool isOnline = false; try { final result = await InternetAddress.lookup(''example.com''); if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { isOnline = true; } else isOnline = false; } on SocketException catch (_) { isOnline = false; } controller.sink.add({result: isOnline}); } void disposeStream() => controller.close(); }