Vérifiez si une connexion Internet est disponible sur l'application Flutter


89

J'ai un appel réseau à exécuter. Mais avant de faire cela, je dois vérifier si l'appareil dispose d'une connectivité Internet.

Voici ce que j'ai fait jusqu'à présent:

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

La méthode ci-dessus ne fonctionne pas.

Réponses:


175

Le plugin de connectivité indique dans sa documentation qu'il ne fournit des informations que s'il y a une connexion réseau, mais pas si le réseau est connecté à Internet

Notez que sur Android, cela ne garantit pas la connexion à Internet. Par exemple, l'application peut avoir un accès wifi, mais il peut s'agir d'un VPN ou d'un WiFi d'hôtel sans accès.

Vous pouvez utiliser

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');
}

2
J'obtiens l'erreur "isNotEmpty n'est pas déclaré dans InternetAddress"
Rissmon Suresh

2
Cela peut-il être réalisé en arrière-plan? Comme si j'avais une file d'attente de tâches en attente d'exécution et en attente d'Internet mais l'application est fermée?
Vidor Vistrom

54
Veuillez noter que google.com n'est pas accessible en Chine et que, par conséquent, l'exemple se bloque s'il est utilisé en Chine. Afin d'élargir votre audience, évitez d'utiliser google.com et utilisez plutôt example.com. résultat final = attendre InternetAddress.lookup ('example.com');
otboss

4
Cela ne fonctionne pas pour moi, if (result.isNotEmpty && result[0].rawAddress.isNotEmpty)retourne vrai lorsqu'il y a du wifi mais pas de connexion Internet.
Denn

5
Oh, oui, j'ai complètement oublié ça! En fait, je pense que je peux continuer à utiliser await, je peux juste ajouter .timeoutaprès lookup().
Michel Feinstein le

67

Pour toute autre personne qui atterrit ici, j'aimerais ajouter à la réponse de Günter Zöchbauer, c'était ma solution pour implémenter un utilitaire pour savoir s'il y a Internet ou pas indépendamment de quoi que ce soit d'autre.

Avertissement:

Je suis nouveau dans Dart et Flutter, donc ce n'est peut-être pas la meilleure approche, mais j'aimerais avoir des commentaires.


Combinaison de flutter_connectivity et de test de connexion de Günter Zöchbauer

Mes exigences

Je ne voulais pas avoir un tas de code répété partout où j'avais besoin de vérifier la connexion et je voulais qu'il mette à jour automatiquement les composants ou tout autre élément qui se soucie de la connexion chaque fois qu'il y avait un changement.

ConnectionStatusSingleton

Nous installons d'abord un Singleton. Si vous n'êtes pas familier avec ce modèle, il y a beaucoup de bonnes informations en ligne à leur sujet. Mais l'essentiel est que vous souhaitez créer une seule instance d'une classe pendant le cycle de vie de l'application et pouvoir l'utiliser n'importe où.

Ce singleton se flutter_connectivityconnecte et écoute les changements de connectivité, puis teste la connexion réseau, puis utilise a StreamControllerpour mettre à jour tout ce qui est important.

Cela ressemble à ceci:

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;
    }
}

Usage

Initialisation

Nous devons d'abord nous assurer que nous appelons l'initialisation de notre singleton. Mais une seule fois. Cela dépend de vous, mais je l'ai fait dans mon application main():

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();   
}

Dans Widgetou ailleurs

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) {
        ...
    }
}

J'espère que quelqu'un d'autre trouvera cela utile!


Exemple de dépôt github: https://github.com/dennmat/flutter-connectiontest-example

Basculez en mode avion dans l'émulateur pour voir le résultat


2
J'ai testé le code et cela fonctionne pour moi. J'aurais besoin de plus d'informations pour m'aider.
dennmat

3
Ahh, ok je le vois. Donc, encore une fois, pour votre future référence, l'erreur que vous publiez est juste l'éditeur essayant d'ouvrir le fichier où il pense que l'erreur s'est produite. La véritable erreur devrait être disponible dans la console de débogage / panneau de trace de la pile de votre éditeur. Donc, je suppose que runApp revient, j'ai supposé qu'il fonctionnerait pendant toute la durée de vie du programme. Étant donné que c'est dans l'ensemble, la suppression n'est pas vraiment nécessaire ici, alors supprimez simplement en connectionStatus.dispose()supposant que vous la configurez main()comme ci-dessus. Mettra à jour l'article et le lien vers l'exemple github.
dennmat

1
Pour détecter simplement si le wifi ou le cellulaire est commuté, vous n'avez besoin que d'une connectivité flottante. Ce wrapper vérifie la connexion après le basculement. Mais n'alertera pas chaque changement de réseau. Si vous utilisez l'émulateur, basculer le mode avion est le moyen le plus simple de perdre la connexion Internet. Si vous utilisez un appareil réel, vous devez vous assurer que vous n'êtes toujours pas connecté à un réseau mobile avec des données.
dennmat

1
Il existe quelques options pour cela, vous pouvez modifier ce qui précède pour utiliser la minuterie pour tester fréquemment. Ou testez simplement fréquemment à l'aide de l'utilitaire Timer. Voir: api.dartlang.org/stable/2.1.0/dart-async/Timer-class.html Une autre option consiste à tester la connexion avant chaque requête que vous envoyez. Bien qu'il semble que vous recherchiez peut-être quelque chose comme des websockets. Quoi qu'il en soit, bonne chance
dennmat

2
Ne devrions-nous pas annuler l'abonnement dans la fonction dispose () du widget? Je vois que cela est fait dans d'autres exemples StreamController comme ici: stackoverflow.com/questions/44788256/updating-data-in-flutter
Oren

36

entrez la description de l'image ici

Exemple complet démontrant à un auditeur la connectivité Internet et sa source.

Crédit à: connectivité et 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();
}

via Firebase, SDK est-il possible?
LOG_TAG

@LOG_TAG Vous n'êtes pas obligé d'utiliser Firebase pour cela.
CopsOnRoad

1
@CopsOnRoad Merci beaucoup. tu as sauvé mon temps.
Nimisha Ranipa le

Map _source = {ConnectivityResult.none: false}; Pourquoi vous avez utilisé "faux" ici
Faruk AYDIN

@CopsOnRoad Merci! J'ai utilisé cette méthode, mais cette méthode me donne la première fois NoInternetConnection! Pourquoi ne m'en donner aucun? Ceci est mon impression de débogage: connectivitéResult.none connectivitéResult.wifi
Faruk AYDIN

19

En utilisant

dependencies:
  connectivity: ^0.4.2

ce que nous avons obtenu des ressources est

      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;
      }

L'avenir est peu problématique pour moi, nous devons le mettre en œuvre à chaque fois comme:

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

Donc, pour résoudre ce problème, j'ai créé une classe qui accepte une fonction avec le paramètre booléen isNetworkPresent comme celui-ci

methodName(bool isNetworkPresent){}

Et la classe utilitaire est

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);
  }
    });
  }
}

Et pour utiliser l'utilitaire de vérification de la connectivité

  fetchPrefrence(bool isNetworkPresent) {
    if(isNetworkPresent){

    }else{

    }
  }

j'utiliserai cette syntaxe

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

17

J'ai trouvé que le simple fait d'utiliser le package de connectivité n'était pas suffisant pour dire si Internet était disponible ou non. Sous Android, il vérifie uniquement s'il y a WIFI ou si les données mobiles sont activées, il ne vérifie pas une connexion Internet réelle. Pendant mes tests, même sans signal mobile, ConnectivityResult.mobile renverrait true.

Avec IOS, mes tests ont révélé que le plugin de connectivité détecte correctement s'il y a une connexion Internet lorsque le téléphone n'a pas de signal, le problème était uniquement avec Android.

La solution que j'ai trouvée était d'utiliser le package data_connection_checker avec le package de connectivité. Cela permet simplement de s'assurer qu'il existe une connexion Internet en faisant des demandes à quelques adresses fiables, le délai d'expiration par défaut pour la vérification est d'environ 10 secondes.

Ma fonction isInternet terminée ressemblait un peu à ceci:

  Future<bool> isInternet() async {
    var connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult == ConnectivityResult.mobile) {
      // I am connected to a mobile network, make sure there is actually a net connection.
      if (await DataConnectionChecker().hasConnection) {
        // Mobile data detected & internet connection confirmed.
        return true;
      } else {
        // Mobile data detected but no internet connection found.
        return false;
      }
    } else if (connectivityResult == ConnectivityResult.wifi) {
      // I am connected to a WIFI network, make sure there is actually a net connection.
      if (await DataConnectionChecker().hasConnection) {
        // Wifi detected & internet connection confirmed.
        return true;
      } else {
        // Wifi detected but no internet connection found.
        return false;
      }
    } else {
      // Neither mobile data or WIFI detected, not internet connection found.
      return false;
    }
  }

La if (await DataConnectionChecker().hasConnection)partie est la même pour les connexions mobiles et wifi et devrait probablement être déplacée vers une fonction distincte. Je n'ai pas fait cela ici pour le rendre plus lisible.

Ceci est ma première réponse Stack Overflow, j'espère que cela aidera quelqu'un.


1
Bienvenue dans stackoverflow. Vous vous demandez simplement quel est l'avantage par rapport à la simple utilisation await DataConnectionChecker().hasConnectionen premier lieu?
herbert

2
La seule raison est que sur IOS, le package de connectivité peut dire à peu près instantanément qu'il n'y a pas de connexion. Si je viens d'utiliser le package data_connection_checker, l'application sur IOS devra attendre que la requête http qu'elle a faite expire, environ 10 secondes, avant de retourner false. Cela peut cependant être acceptable dans certains cas. Le package de connectivité peut également indiquer si vous utilisez le WIFI ou des données mobiles que je n'ai pas besoin de savoir ici mais qu'il peut être utile de savoir.
abernee le

Cela fonctionne parfaitement avec quelques modifications de syntaxe dans le code ci-dessus. 1. vous devez changer Future <Bool> en future <bool>), car les types sont en minuscules. 2. Ajoutez un point-virgule (;) pour la quatrième dernière instruction de retour.
TDM

Merci TDM, j'ai édité la réponse avec vos modifications.
abernee le

6

J'ai créé un package qui (je pense) traite de manière fiable ce problème.

Le paquet sur pub.dev

Le package sur GitHub

La discussion est la bienvenue. Vous pouvez utiliser le suivi des problèmes sur GitHub.


Je ne pense plus que ce ci-dessous soit une méthode fiable:


Je veux ajouter quelque chose à la réponse de @ Oren : vous devriez vraiment ajouter une autre capture, qui capturera toutes les autres exceptions (juste pour être sûr), OU supprimez simplement le type d'exception et utilisez une capture, qui traite toutes les exceptions:

Cas 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;
}

ou encore plus simple ...

Cas 2:


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

5

J'ai créé une classe de base pour l'état du widget

Utilisation au lieu d' State<LoginPage>utiliser, BaseState<LoginPage> puis utilisez simplement la variable booléenne isOnline

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

Tout d'abord, ajoutez le plugin de connectivité:

dependencies:
  connectivity: ^0.4.3+2

Ajoutez ensuite la classe BaseState

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 {

  void castStatefulWidget();

  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;
  }
}

Et vous devez lancer le widget dans votre état comme ceci

@override
  void castStatefulWidget() {
    // ignore: unnecessary_statements
    widget is StudentBoardingPage;
  }

2
comment puis-je utiliser ce cours?
DolDurma

@DolDurma Ajoutez-le simplement et importez-le, puis au lieu de State <LoginPage> utilisez BaseState <LoginPage> puis utilisez simplement la variable booléenne isOnline
amorenew

avec ce code, je ne peux pas obtenir de valeurs widget. par exemple: RegisterBloc get _registerBloc => widget.registerBloc;j'obtiens cette erreur error: The getter 'registerBloc' isn't defined for the class 'StatefulWidget'. (undefined_getter at lib\screens\fragmemt_register\view\register_mobile_number.dart:29)voir cette implémentation:class _FragmentRegisterMobileNumberState extends BaseState<FragmentRegisterMobileNumber> with SingleTickerProviderStateMixin { RegisterBloc get _registerBloc => widget.registerBloc;
DolDurma

@DolDurma Je ne sais pas quel est le problème sans un échantillon GitHub car cette information ne suffit pas
amorenew

1
s'il vous plaît vérifier ce dépôt et me montrer comment puis-je utiliser is_onlinepour me connecter à la console github.com/MahdiPishguy/flutter-connectivity-sample
DolDurma

3

Suite à la réponse de @dennmatt , j'ai remarqué que cela InternetAddress.lookuppouvait donner des résultats positifs même si la connexion Internet était désactivée - je l'ai testé en me connectant de mon simulateur à mon WiFi domestique, puis en déconnectant le câble de mon routeur. Je pense que la raison est que le routeur met en cache les résultats de recherche de domaine afin de ne pas avoir à interroger les serveurs DNS à chaque demande de recherche.

Quoi qu'il en soit, si vous utilisez Firestore comme moi, vous pouvez remplacer le bloc try-SocketException-catch par une transaction vide et attraper TimeoutExceptions:

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;
}

Veuillez également noter qu'il previousConnectionest défini avant la vérification de réseau asynchrone, donc théoriquement, s'il checkConnection()est appelé plusieurs fois en peu de temps, il peut y en avoir plusieurs hasConnection=truedans une ligne ou plusieurs hasConnection=falsedans une ligne. Je ne sais pas si @dennmatt l'a fait exprès ou non, mais dans notre cas d'utilisation, il n'y a pas eu d'effets secondaires ( setStaten'a été appelé que deux fois avec la même valeur).


3

La connectivité: le forfait ne garantit pas la connexion Internet réelle (il peut s'agir simplement d'une connexion wifi sans accès Internet).

Citation de la documentation:

Notez que sur Android, cela ne garantit pas la connexion à Internet. Par exemple, l'application peut avoir un accès wifi, mais il peut s'agir d'un VPN ou d'un WiFi d'hôtel sans accès.

Si vous avez vraiment besoin de vérifier la connexion à Internet www, le meilleur choix serait

Package data_connection_checker


1

Voici ma solution, elle vérifie la connectivité Internet ainsi que la connexion de données, j'espère que vous l'aimerez.

Tout d'abord, ajoutez des dépendances dans votre pubsec.yaml
dependencies:        
    data_connection_checker:
Et voici le dessin principal de ma solution
import 'dart:async';

import 'package:data_connection_checker/data_connection_checker.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Data Connection Checker",
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  StreamSubscription<DataConnectionStatus> listener;

  var Internetstatus = "Unknown";

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
//    _updateConnectionStatus();
      CheckInternet();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    listener.cancel();
    super.dispose();
  }

  CheckInternet() async {
    // Simple check to see if we have internet
    print("The statement 'this machine is connected to the Internet' is: ");
    print(await DataConnectionChecker().hasConnection);
    // returns a bool

    // We can also get an enum instead of a bool
    print("Current status: ${await DataConnectionChecker().connectionStatus}");
    // prints either DataConnectionStatus.connected
    // or DataConnectionStatus.disconnected

    // This returns the last results from the last call
    // to either hasConnection or connectionStatus
    print("Last results: ${DataConnectionChecker().lastTryResults}");

    // actively listen for status updates
    listener = DataConnectionChecker().onStatusChange.listen((status) {
      switch (status) {
        case DataConnectionStatus.connected:
          Internetstatus="Connectd TO THe Internet";
          print('Data connection is available.');
          setState(() {

          });
          break;
        case DataConnectionStatus.disconnected:
          Internetstatus="No Data Connection";
          print('You are disconnected from the internet.');
          setState(() {

          });
          break;
      }
    });

    // close listener after 30 seconds, so the program doesn't run forever
//    await Future.delayed(Duration(seconds: 30));
//    await listener.cancel();
    return await await DataConnectionChecker().connectionStatus;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Data Connection Checker"),
      ),
      body: Container(
        child: Center(
          child: Text("$Internetstatus"),
        ),
      ),
    );
  }
}

1

J'ai eu un problème avec les solutions proposées, l'utilisation lookupne renvoie pas toujours la valeur attendue.

Cela est dû à la mise en cache DNS, la valeur de l'appel est mise en cache et au lieu de faire un appel approprié lors du prochain essai, il rend la valeur mise en cache. Bien sûr, c'est un problème ici car cela signifie que si vous perdez la connectivité et que vous l'appelez, lookupil pourrait toujours renvoyer la valeur mise en cache comme si vous aviez Internet, et inversement, si vous reconnectez votre Internet après avoir lookuprenvoyé null, il renverra toujours null pendant la durée du cache, ce qui peut durer quelques minutes, même si vous disposez maintenant d'Internet.

TL; DR: lookupretourner quelque chose ne signifie pas nécessairement que vous avez Internet, et ne rien renvoyer ne signifie pas nécessairement que vous n'avez pas Internet. Ce n'est pas fiable.

J'ai implémenté la solution suivante en m'inspirant du data_connection_checkerplugin:

 /// If any of the pings returns true then you have internet (for sure). If none do, you probably don't.
  Future<bool> _checkInternetAccess() {
    /// We use a mix of IPV4 and IPV6 here in case some networks only accept one of the types.
    /// Only tested with an IPV4 only network so far (I don't have access to an IPV6 network).
    final List<InternetAddress> dnss = [
      InternetAddress('8.8.8.8', type: InternetAddressType.IPv4), // Google
      InternetAddress('2001:4860:4860::8888', type: InternetAddressType.IPv6), // Google
      InternetAddress('1.1.1.1', type: InternetAddressType.IPv4), // CloudFlare
      InternetAddress('2606:4700:4700::1111', type: InternetAddressType.IPv6), // CloudFlare
      InternetAddress('208.67.222.222', type: InternetAddressType.IPv4), // OpenDNS
      InternetAddress('2620:0:ccc::2', type: InternetAddressType.IPv6), // OpenDNS
      InternetAddress('180.76.76.76', type: InternetAddressType.IPv4), // Baidu
      InternetAddress('2400:da00::6666', type: InternetAddressType.IPv6), // Baidu
    ];

    final Completer<bool> completer = Completer<bool>();

    int callsReturned = 0;
    void onCallReturned(bool isAlive) {
      if (completer.isCompleted) return;

      if (isAlive) {
        completer.complete(true);
      } else {
        callsReturned++;
        if (callsReturned >= dnss.length) {
          completer.complete(false);
        }
      }
    }

    dnss.forEach((dns) => _pingDns(dns).then(onCallReturned));

    return completer.future;
  }

  Future<bool> _pingDns(InternetAddress dnsAddress) async {
    const int dnsPort = 53;
    const Duration timeout = Duration(seconds: 3);

    Socket socket;
    try {
      socket = await Socket.connect(dnsAddress, dnsPort, timeout: timeout);
      socket?.destroy();
      return true;
    } on SocketException {
      socket?.destroy();
    }
    return false;
  }

L'appel à _checkInternetAccessprend au plus une durée de timeoutpour se terminer (3 secondes ici), et si nous pouvons atteindre l'un des DNS, il se terminera dès que le premier est atteint, sans attendre les autres (car en atteindre un suffit pour sachez que vous avez Internet). Tous les appels à _pingDnsse font en parallèle.

Cela semble bien fonctionner sur un réseau IPV4, et quand je ne peux pas le tester sur un réseau IPV6 (je n'ai pas accès à un), je pense que cela devrait toujours fonctionner. Cela fonctionne également sur les versions en mode version, mais je dois encore soumettre mon application à Apple pour voir s'ils rencontrent un problème avec cette solution.

Cela devrait également fonctionner dans la plupart des pays (y compris la Chine), si cela ne fonctionne pas dans l'un d'entre eux, vous pouvez ajouter un DNS à la liste accessible depuis votre pays cible.


1

J'ai finalement ( mais à contrecœur ) choisi la solution donnée par @abernee dans une réponse précédente à cette question. J'essaie toujours d'utiliser le moins de packages externes possible dans mes projets - car je sais que les packages externes sont les seuls points d'échec [potentiels] dans le logiciel que je crée. Donc, créer un lien vers DEUX packages externes juste pour une implémentation simple comme celle-ci n'a pas été facile pour moi .

Néanmoins, j'ai pris le code d'abernee et l'ai modifié pour le rendre plus léger et plus sensé. Par sensé, je veux dire qu'il consomme la puissance du package Connectivity dans sa fonction, mais la gaspille ensuite en interne en ne renvoyant pas les résultats les plus précieux de ce package (c'est-à-dire l'identification du réseau). Voici donc la version modifiée de la solution d'abernee:

import 'package:connectivity/connectivity.dart';
import 'package:data_connection_checker/data_connection_checker.dart';


// 'McGyver' - the ultimate cool guy (the best helper class any app can ask for).
class McGyver {

  static Future<Map<String, dynamic>> checkInternetAccess() async {
    //* ////////////////////////////////////////////////////////////////////////////////////////// *//
    //*   INFO: ONLY TWO return TYPES for Map 'dynamic' value => <bool> and <ConnectivityResult>   *//
    //* ////////////////////////////////////////////////////////////////////////////////////////// *//
    Map<String, dynamic> mapCon;
    final String isConn = 'isConnected', netType = 'networkType';
    ConnectivityResult conRes = await (Connectivity().checkConnectivity());
    switch (conRes) {
      case ConnectivityResult.wifi:   //* WiFi Network: true !!
        if (await DataConnectionChecker().hasConnection) {   //* Internet Access: true !!
          mapCon = Map.unmodifiable({isConn: true, netType: ConnectivityResult.wifi});
        } else {
          mapCon = Map.unmodifiable({isConn: false, netType: ConnectivityResult.wifi});
        }
        break;
      case ConnectivityResult.mobile:   //* Mobile Network: true !!
        if (await DataConnectionChecker().hasConnection) {   //* Internet Access: true !!
          mapCon = Map.unmodifiable({isConn: true, netType: ConnectivityResult.mobile});
        } else {
          mapCon = Map.unmodifiable({isConn: false, netType: ConnectivityResult.mobile});
        }
        break;
      case ConnectivityResult.none:   //* No Network: true !!
        mapCon = Map.unmodifiable({isConn: false, netType: ConnectivityResult.none});
        break;
    }
    return mapCon;
  }

}

Ensuite, vous utiliseriez cette fonction statique via un simple appel de n'importe où dans votre code comme suit:

bool isConn; ConnectivityResult netType;
McGyver.checkInternetAccess().then(
  (mapCIA) {  //* 'mapCIA' == amalgamation for 'map' from 'CheckInternetAccess' function result.
    debugPrint("'mapCIA' Keys: ${mapCIA.keys}");
    isConn = mapCIA['isConnected'];
    netType = mapCIA['networkType'];
  }
);
debugPrint("Internet Access: $isConn   |   Network Type: $netType");

C'est dommage que vous deviez créer un lien vers DEUX PACKAGES EXTERNES pour obtenir cette fonctionnalité très basique dans votre projet Flutter - mais je suppose que pour l'instant c'est le meilleur que nous ayons. En fait, je préfère le package Data Connection Checker au package Connectivity - mais (au moment de publier ceci) le premier manquait cette fonction d'identification réseau très importante dont j'ai besoin dans le package Connectivity. C'est la raison pour laquelle j'ai opté pour cette approche [temporairement].


0

J'essaie simplement de simplifier le code à l'aide du package de connectivité dans Flutter.

import 'package:connectivity/connectivity.dart';

var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
  // I am connected to a mobile network.
} else if (connectivityResult == ConnectivityResult.wifi) {
  // I am connected to a wifi network.
} else {
  // I am not connected to the internet
}

Le problème avec cela sur Android est que ce n'est pas parce que vous êtes connecté via wifi ou mobile que vous êtes connecté à Internet.
Megadec

1
@Megadec tristement oui c'est le seul problème :(
devDeejay

0

réponse tardive, mais utilisez ce package pour vérifier. Nom du package: data_connection_checker

dans votre fichier pubspec.yuml:

dependencies:
    data_connection_checker: ^0.3.4

créez un fichier appelé connection.dart ou n'importe quel nom de votre choix. importer le package:

import 'package:data_connection_checker/data_connection_checker.dart';

vérifiez s'il y a une connexion Internet ou non:

print(await DataConnectionChecker().hasConnection);

0

J'ai utilisé le package data_connection_checker pour vérifier l'accès internet même si la connexion disponible par wifi ou mobile, ça marche bien: voici le code pour vérifier la connexion:

bool result = await DataConnectionChecker().hasConnection;
if(result == true) {
   print('YAY! Free cute dog pics!');
} else {
   print('No internet :( Reason:');
   print(DataConnectionChecker().lastTryResults);
}

rendez-vous sur le paquet si vous voulez plus d'informations. Package de vérificateur de connexion de données


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.