Überprüfen Sie, ob in der Flutter-App eine Internetverbindung verfügbar ist

89

Ich muss einen Netzwerkanruf ausführen. Aber bevor ich das mache, muss ich überprüfen, ob das Gerät über eine Internetverbindung verfügt.

Das habe ich bisher gemacht:

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

Die obige Methode funktioniert nicht.

Rissmon Suresh
quelle

Antworten:

175

Das Konnektivitäts- Plugin gibt in seinen Dokumenten an, dass es nur Informationen bereitstellt, wenn eine Netzwerkverbindung besteht, nicht jedoch, wenn das Netzwerk mit dem Internet verbunden ist

Beachten Sie, dass unter Android keine Verbindung zum Internet garantiert wird. Beispielsweise verfügt die App möglicherweise über WLAN-Zugang, es handelt sich jedoch möglicherweise um ein VPN oder ein Hotel-WLAN ohne Zugang.

Sie können verwenden

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');
}
Günter Zöchbauer
quelle
2
Ich erhalte die Fehlermeldung "isNotEmpty ist nicht in InternetAddress deklariert"
Rissmon Suresh
2
Kann dies im Hintergrund erreicht werden? Als ob ich eine Warteschlange mit Aufgaben habe, die zur Ausführung anstehen und auf das Internet warten, aber die App geschlossen ist?
Vidor Vistrom
54
Bitte beachten Sie, dass google.com in China nicht zugänglich ist und das Beispiel daher hängen bleibt, wenn es in China verwendet wird. Um Ihre Zielgruppe zu erweitern, vermeiden Sie bitte die Verwendung von google.com und verwenden Sie stattdessen example.com. Endergebnis = warte auf InternetAddress.lookup ('example.com');
otboss
4
Dies funktioniert bei mir nicht if (result.isNotEmpty && result[0].rawAddress.isNotEmpty), wenn true, aber keine Internetverbindung vorhanden ist.
Denn
5
Oh ja, das habe ich komplett vergessen! Eigentlich glaube ich , dass ich halten kann mit await, ich kann einfach append .timeoutnach lookup().
Michel Feinstein
67

Für alle anderen, die hier landen, möchte ich die Antwort von Günter Zöchbauer ergänzen. Dies war meine Lösung für die Implementierung eines Dienstprogramms, um zu wissen, ob es Internet gibt oder nicht, unabhängig von irgendetwas anderem.

Haftungsausschluss:

Ich bin sowohl bei Dart als auch bei Flutter neu, daher ist dies möglicherweise nicht der beste Ansatz, würde aber gerne Feedback erhalten.


Kombination von flutter_connectivity und Günter Zöchbauers Verbindungstest

Meine Anforderungen

Ich wollte nirgendwo, wo ich die Verbindung überprüfen musste, eine Menge wiederholten Codes haben, und ich wollte, dass er automatisch Komponenten oder andere Elemente aktualisiert, die sich bei jeder Änderung um die Verbindung kümmerten.

ConnectionStatusSingleton

Zuerst richten wir einen Singleton ein. Wenn Sie mit diesem Muster nicht vertraut sind, gibt es online viele gute Informationen darüber. Das Wesentliche ist jedoch, dass Sie eine einzelne Instanz einer Klasse während des Anwendungslebenszyklus erstellen und überall verwenden möchten.

Dieser Singleton hakt sich ein flutter_connectivityund wartet auf Konnektivitätsänderungen, testet dann die Netzwerkverbindung StreamControllerund aktualisiert mit a alles, was wichtig ist.

Es sieht aus wie das:

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

Verwendung

Initialisierung

Zuerst müssen wir sicherstellen, dass wir die Initialisierung unseres Singletons aufrufen. Aber nur einmal. Dies liegt ganz bei Ihnen, aber ich habe es in meiner App getan 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();   
}

In Widgetoder anderswo

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

Hoffe, jemand anderes findet das nützlich!


Beispiel für ein Github-Repo: https://github.com/dennmat/flutter-connectiontest-example

Schalten Sie den Flugzeugmodus im Emulator um, um das Ergebnis anzuzeigen

dennmat
quelle
2
Testete den Code und es funktioniert für mich Ich würde mehr Informationen brauchen, um zu helfen.
Dennmat
3
Ahh, ok ich sehe es. Für Ihre zukünftige Bezugnahme ist der Fehler, den Sie veröffentlichen, nur der Editor, der versucht, die Datei dort zu öffnen, wo der Fehler aufgetreten ist. Der eigentliche Fehler sollte in der Debug-Konsole / im Stack-Trace-Panel Ihres Editors verfügbar sein. Ich denke, runApp gibt zurück, dass ich davon ausgegangen bin, dass es für die gesamte Lebensdauer des Programms ausgeführt wird. Da dies hauptsächlich der Fall ist, ist die Entsorgung hier nicht wirklich erforderlich. Entfernen connectionStatus.dispose()Sie sie einfach, vorausgesetzt, Sie richten sie main()wie oben beschrieben ein. Aktualisiert den Beitrag und verlinkt auf das Github-Beispiel.
Dennmat
1
Um nur zu erkennen, ob WLAN oder Mobilfunk geschaltet wird, benötigen Sie nur eine Flatterverbindung. Dieser Wrapper überprüft die Verbindung, nachdem der Wechsel erfolgt ist. Wird aber nicht jede Netzwerkänderung alarmieren. Wenn Sie den Emulator verwenden, ist das Umschalten des Flugzeugmodus der einfachste Weg, um die Internetverbindung zu verlieren. Wenn Sie sich auf einem tatsächlichen Gerät befinden, müssen Sie sicherstellen, dass Sie noch nicht mit einem Mobilfunknetz mit Daten verbunden sind.
Dennmat
1
Dafür gibt es einige Optionen. Sie können die oben genannten Optionen ändern, um Timer zum häufigen Testen zu verwenden. Oder testen Sie einfach häufig mit dem Timer-Dienstprogramm. Siehe: api.dartlang.org/stable/2.1.0/dart-async/Timer-class.html Eine weitere Option ist das Testen der Verbindung vor jeder von Ihnen gesendeten Anfrage. Obwohl es so aussieht, als ob Sie nach etwas wie Websockets suchen. Wie auch immer, viel Glück
dennmat
2
Sollten wir das Abonnement nicht in der Funktion dispose () des Widgets kündigen? Ich sehe, dass dies in anderen StreamController-Beispielen wie hier gemacht wird: stackoverflow.com/questions/44788256/updating-data-in-flutter
Oren
36

Geben Sie hier die Bildbeschreibung ein

Vollständiges Beispiel für einen Hörer der Internetverbindung und ihrer Quelle.

Dank an: Konnektivität und 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();
}
CopsOnRoad
quelle
über Firebase, SDK ist es möglich?
LOG_TAG
@LOG_TAG Hierfür müssen Sie Firebase nicht verwenden.
CopsOnRoad
1
@CopsOnRoad Vielen Dank. Du hast mir Zeit gespart.
Nimisha Ranipa
Map _source = {ConnectivityResult.none: false}; Warum Sie hier "falsch" verwendet haben
Faruk AYDIN
@CopsOnRoad Danke! Ich habe diese Methode verwendet, aber diese Methode gibt mir zum ersten Mal NoInternetConnection! Warum gibst du mir zuerst keine? Dies ist mein Debug-Druck: KonnektivitätResult.none KonnektivitätResult.wifi KonnektivitätResult.wifi.
Faruk AYDIN
19

Verwenden von

dependencies:
  connectivity: ^0.4.2

Was wir aus Ressourcen bekommen haben, ist

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

Die Zukunft ist für mich wenig problematisch, wir müssen sie jedes Mal umsetzen wie:

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

Um dieses Problem zu lösen, habe ich eine Klasse erstellt, die eine Funktion mit dem booleschen isNetworkPresent-Parameter wie diesem akzeptiert

methodName(bool isNetworkPresent){}

Und die Utility-Klasse ist

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

Und um die Konnektivität zu nutzen

  fetchPrefrence(bool isNetworkPresent) {
    if(isNetworkPresent){

    }else{

    }
  }

Ich werde diese Syntax verwenden

NetworkCheck networkCheck = new NetworkCheck();
networkCheck.checkInternet(fetchPrefrence)
Tushar Pandey
quelle
17

Ich stellte fest, dass die Verwendung des Konnektivitätspakets nicht ausreicht, um festzustellen, ob das Internet verfügbar ist oder nicht. In Android wird nur geprüft, ob WIFI vorhanden ist oder ob mobile Daten aktiviert sind. Es wird nicht nach einer tatsächlichen Internetverbindung gesucht. Während meiner Tests würde ConnectivityResult.mobile auch ohne mobiles Signal true zurückgeben.

Bei IOS haben meine Tests ergeben, dass das Konnektivitäts-Plugin korrekt erkennt, ob eine Internetverbindung besteht, wenn das Telefon kein Signal hat. Das Problem trat nur bei Android auf.

Die Lösung, die ich gefunden habe, bestand darin, das Paket data_connection_checker zusammen mit dem Konnektivitätspaket zu verwenden. Dies stellt lediglich sicher, dass eine Internetverbindung besteht, indem Anfragen an einige zuverlässige Adressen gestellt werden. Das Standardzeitlimit für die Überprüfung beträgt ca. 10 Sekunden.

Meine fertige isInternet-Funktion sah ungefähr so ​​aus:

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

Das if (await DataConnectionChecker().hasConnection)Teil ist für mobile und WLAN-Verbindungen gleich und sollte wahrscheinlich in eine separate Funktion verschoben werden. Ich habe das hier nicht getan, um es besser lesbar zu machen.

Dies ist meine erste Antwort auf den Stapelüberlauf. Ich hoffe, sie hilft jemandem.

Abernee
quelle
1
Willkommen bei stackoverflow. Ich frage mich nur, was ist der Vorteil gegenüber await DataConnectionChecker().hasConnectionder erstmaligen Verwendung?
Herbert
2
Der einzige Grund ist, dass das Konnektivitätspaket unter IOS ziemlich sofort erkennen kann, dass keine Verbindung besteht. Wenn ich nur das Paket data_connection_checker verwenden würde, müsste die App unter IOS etwa 10 Sekunden warten, bis die http-Anforderung abgelaufen ist, bevor sie false zurückgibt. Dies kann jedoch in einigen Fällen akzeptabel sein. Das Konnektivitätspaket kann auch erkennen, ob Sie WIFI oder mobile Daten verwenden, die ich hier nicht wissen muss, die aber möglicherweise nützlich sind.
Abernee
Dies funktioniert perfekt mit wenigen Syntaxänderungen im obigen Code. 1. Sie müssen Future <Bool> in future <bool>) ändern, da Typen in Kleinbuchstaben geschrieben sind. 2. Fügen Sie das Semikolon (;) für die 4. letzte return-Anweisung hinzu.
TDM
Danke TDM, ich habe die Antwort mit Ihren Änderungen bearbeitet.
Abernee
6

Ich habe ein Paket erstellt, das (glaube ich) dieses Problem zuverlässig behandelt.

Das Paket auf pub.dev

Das Paket auf GitHub

Diskussion ist sehr willkommen. Sie können den Issues Tracker auf GitHub verwenden.


Ich halte dies im Folgenden nicht mehr für eine zuverlässige Methode:


Möchten Sie der Antwort von @ Oren etwas hinzufügen : Sie sollten wirklich noch einen Fang hinzufügen, der alle anderen Ausnahmen abfängt (nur um sicher zu gehen), ODER den Ausnahmetyp ganz entfernen und einen Fang verwenden, der alle Ausnahmen behandelt:

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

oder noch einfacher ...

Fall 2:


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

Ich habe eine Basisklasse für den Widget-Status erstellt

Verwendung statt State<LoginPage>Verwendung, verwenden Sie BaseState<LoginPage> einfach die boolesche Variable isOnline

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

Fügen Sie zunächst das Konnektivitäts-Plugin hinzu:

dependencies:
  connectivity: ^0.4.3+2

Fügen Sie dann die BaseState-Klasse hinzu

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

Und Sie müssen das Widget in Ihrem Bundesstaat so umwandeln

@override
  void castStatefulWidget() {
    // ignore: unnecessary_statements
    widget is StudentBoardingPage;
  }
amorenew
quelle
2
Wie kann ich diese Klasse verwenden?
DolDurma
@DolDurma Fügen Sie es einfach hinzu und importieren Sie es. Verwenden Sie dann anstelle von State <LoginPage> BaseState <LoginPage> und verwenden Sie dann einfach die boolesche Variable isOnline
amorenew
Mit diesem Code kann ich keine Wertsachen bekommen widget. Zum Beispiel: RegisterBloc get _registerBloc => widget.registerBloc;Ich bekomme diesen Fehler, error: The getter 'registerBloc' isn't defined for the class 'StatefulWidget'. (undefined_getter at lib\screens\fragmemt_register\view\register_mobile_number.dart:29)siehe diese Implementierung:class _FragmentRegisterMobileNumberState extends BaseState<FragmentRegisterMobileNumber> with SingleTickerProviderStateMixin { RegisterBloc get _registerBloc => widget.registerBloc;
DolDurma
@ DolDurma Ich bin nicht sicher, was das Problem ohne ein GitHub-Beispiel ist, weil diese Informationen nicht ausreichen
amorenew
1
Bitte überprüfen Sie dieses Repo und zeigen Sie mir, wie ich mich is_onlinein der Konsole anmelden kann. github.com/MahdiPishguy/flutter-connectivity-sample
DolDurma
3

Nach der Antwort von @dennmatt habe ich das bemerktInternetAddress.lookup möglicherweise erfolgreiche Ergebnisse zurückgegeben werden, selbst wenn die Internetverbindung ist. Ich habe sie getestet, indem ich eine Verbindung von meinem Simulator zu meinem Heim-WLAN hergestellt und dann das Kabel meines Routers abgezogen habe. Ich denke, der Grund dafür ist, dass der Router die Ergebnisse der Domänensuche zwischenspeichert, sodass er die DNS-Server nicht bei jeder Suchanforderung abfragen muss.

Wenn Sie Firestore wie ich verwenden, können Sie den try-SocketException-catch-Block durch eine leere Transaktion ersetzen und TimeoutExceptions abfangen:

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

previousConnectionBeachten Sie auch, dass dies vor der asynchronen Intenet-Prüfung festgelegt wird. Wenn checkConnection()es also theoretisch in kurzer Zeit mehrmals aufgerufen wird, kann es mehrere hasConnection=truein einer Reihe oder mehrere hasConnection=falsein einer Reihe geben. Ich bin nicht sicher, ob @dennmatt es absichtlich getan hat oder nicht, aber in unserem Anwendungsfall gab es keine Nebenwirkungen ( setStatewurde nur zweimal mit demselben Wert aufgerufen).

Oren
quelle
3

Das Konnektivitätspaket garantiert nicht die tatsächliche Internetverbindung (könnte nur eine WLAN-Verbindung ohne Internetzugang sein).

Zitat aus der Dokumentation:

Beachten Sie, dass unter Android keine Verbindung zum Internet garantiert wird. Beispielsweise verfügt die App möglicherweise über WLAN-Zugang, es handelt sich jedoch möglicherweise um ein VPN oder ein Hotel-WLAN ohne Zugang.

Wenn Sie wirklich die Verbindung zum Internet überprüfen müssen, ist die bessere Wahl

Paket data_connection_checker

Andrew
quelle
1

Hier ist meine Lösung Es überprüft die Internetverbindung sowie die Datenverbindung. Ich hoffe, es gefällt Ihnen.

Fügen Sie zunächst Abhängigkeiten in Ihre pubsec.yaml ein
dependencies:        
    data_connection_checker:
Und hier ist der Hauptpfeil meiner Lösung
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"),
        ),
      ),
    );
  }
}
Tirth Raj
quelle
1

Ich hatte ein Problem mit den vorgeschlagenen Lösungen. Die Verwendung lookupgibt nicht immer den erwarteten Wert zurück.

Dies ist auf das DNS-Caching zurückzuführen. Der Wert des Anrufs wird zwischengespeichert, und anstatt beim nächsten Versuch einen ordnungsgemäßen Anruf auszuführen, wird der zwischengespeicherte Wert zurückgegeben. Dies ist hier natürlich ein Problem, da es bedeutet, dass bei einem Verbindungsverlust und einem Anruf lookupder zwischengespeicherte Wert immer noch zurückgegeben werden kann, als ob Sie Internet hätten. Wenn Sie Ihr Internet nach der lookupRückgabe von null erneut verbinden, wird für die Dauer des Vorgangs immer noch null zurückgegeben Cache, der einige Minuten dauern kann, selbst wenn Sie jetzt über Internet verfügen.

TL; DR: lookupEtwas zurückzugeben bedeutet nicht unbedingt, dass Sie Internet haben, und etwas zurückzugeben bedeutet nicht unbedingt, dass Sie kein Internet haben. Es ist nicht zuverlässig.

Ich habe die folgende Lösung implementiert, indem ich mich vom data_connection_checkerPlugin inspirieren ließ :

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

Der Anruf _checkInternetAccessdauert höchstens timeout3 Sekunden (hier 3 Sekunden). Wenn wir einen der DNS erreichen können, wird er abgeschlossen, sobald der erste erreicht ist, ohne auf die anderen zu warten (da das Erreichen eines Anrufs ausreicht, um einen zu erreichen weiß, dass Sie Internet haben). Alle Anrufe _pingDnswerden parallel getätigt.

Es scheint in einem IPV4-Netzwerk gut zu funktionieren, und wenn ich es in einem IPV6-Netzwerk nicht testen kann (ich habe keinen Zugriff auf eines), denke ich, dass es immer noch funktionieren sollte. Es funktioniert auch bei Builds im Release-Modus, aber ich muss meine App noch bei Apple einreichen, um festzustellen, ob Probleme mit dieser Lösung auftreten.

Es sollte auch in den meisten Ländern (einschließlich China) funktionieren. Wenn es in einem nicht funktioniert, können Sie der Liste, auf die von Ihrem Zielland aus zugegriffen werden kann, einen DNS hinzufügen.

QUentin
quelle
1

Ich habe mich letztendlich ( wenn auch widerstrebend ) für die Lösung entschieden, die @abernee in einer früheren Antwort auf diese Frage gegeben hat. Ich versuche immer, so wenig externe Pakete wie möglich in meinen Projekten zu verwenden - da ich weiß, dass externe Pakete die einzigen [potenziellen] Fehlerquellen in der von mir erstellten Software sind. Es war für mich nicht einfach, nur für eine einfache Implementierung wie diese auf ZWEI externe Pakete zu verlinken .

Trotzdem habe ich den Code von abernee genommen und geändert, um ihn schlanker und sinnvoller zu machen. Mit vernünftig meine ich, dass er die Leistung des Konnektivitätspakets in seiner Funktion verbraucht , diese dann aber intern verschwendet, indem er nicht die wertvollsten Ausgaben dieses Pakets zurückgibt (dh die Netzwerkidentifikation). Hier ist also die modifizierte Version von Abernees Lösung:

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

}

Dann würden Sie diese statische Funktion über einen einfachen Aufruf von einer beliebigen Stelle in Ihrem Code wie folgt verwenden:

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

Es ist schade, dass Sie auf ZWEI EXTERNE PAKETE verlinken müssen , um diese grundlegende Funktionalität in Ihrem Flutter-Projekt zu erhalten - aber ich denke, dies ist das Beste, was wir haben. Eigentlich bevorzuge ich das Data Connection Checker- Paket gegenüber dem Connectivity- Paket - aber (zum Zeitpunkt der Veröffentlichung) fehlte dem ersteren die sehr wichtige Netzwerkidentifikationsfunktion , die ich für das Connectivity-Paket benötige. Dies ist der Grund, warum ich [vorübergehend] diesen Ansatz gewählt habe.

SilSur
quelle
0

Ich versuche nur, den Code mithilfe des Konnektivitätspakets in Flutter zu vereinfachen .

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
}
devDeejay
quelle
Das Problem bei Android ist jedoch, dass nur, weil Sie über WLAN oder Handy verbunden sind, dies nicht bedeutet, dass Sie mit dem Internet verbunden sind.
Megadec
1
@ Megadec leider ja das ist das einzige Problem :(
devDeejay
0

späte Antwort, aber verwenden Sie dieses Paket, um zu überprüfen. Paketname: data_connection_checker

in Ihrer pubspec.yuml-Datei:

dependencies:
    data_connection_checker: ^0.3.4

Erstellen Sie eine Datei mit dem Namen connection.dart oder einem beliebigen Namen. Importieren Sie das Paket:

import 'package:data_connection_checker/data_connection_checker.dart';

Überprüfen Sie, ob eine Internetverbindung besteht oder nicht:

print(await DataConnectionChecker().hasConnection);
hekmat
quelle
0

Ich habe das Paket data_connection_checker verwendet, um den Internetzugang zu überprüfen, auch wenn die über WLAN oder Mobiltelefon verfügbare Verbindung gut funktioniert: Hier ist der Code zum Überprüfen der Verbindung:

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

Gehen Sie über das Paket, wenn Sie weitere Informationen wünschen. Datenverbindungsprüfpaket

Muhamad Haydar Jawad
quelle