Проверьте, доступно ли подключение к Интернету в приложении Flutter

У меня есть сетевой вызов, который будет выполнен. Но перед этим мне нужно проверить, есть ли у устройства подключение к интернету.

Это то, что я сделал до сих пор:

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

Выше метод не работает.

30 ответов

Решение

connectivity В своих документах плагин заявляет, что он предоставляет информацию только при наличии сетевого подключения, но не при подключении сети к Интернету.

Обратите внимание, что на Android это не гарантирует подключение к Интернету. Например, приложение может иметь доступ к Wi-Fi, но это может быть VPN или гостиничный WiFi без доступа.

Ты можешь использовать

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

Для всех, кто приземлится здесь, я хотел бы добавить к ответу Гюнтера Цохбауэра, что это было мое решение для реализации утилиты, чтобы узнать, есть ли интернет или нет, независимо от чего-либо еще.

Отказ от ответственности:

Я новичок в Dart и Flutter, так что, возможно, это не лучший подход, но хотелось бы получить обратную связь.


Сочетание flutter_connectivity и теста соединения Гюнтера Цохбауэра

Мои требования

Я не хотел иметь кучу повторяющегося кода везде, где мне нужно было проверять соединение, и я хотел, чтобы он автоматически обновлял компоненты или что-нибудь еще, что заботилось о соединении всякий раз, когда происходило изменение.

ConnectionStatusSingleton

Сначала мы устанавливаем синглтон. Если вы не знакомы с этим паттерном, в Интернете есть много полезной информации о них. Но суть в том, что вы хотите создать один экземпляр класса в течение жизненного цикла приложения и иметь возможность использовать его где угодно.

Этот синглтон зацепляет flutter_connectivity и прослушивает изменения подключения, затем проверяет сетевое подключение, затем использует StreamController обновить все, что волнует.

Это выглядит так:

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

использование

инициализация

Сначала мы должны убедиться, что мы вызываем инициализацию нашего синглтона. Но только один раз. Это зависит от вас, но я сделал это в моем приложении 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();   
}

В Widget или в другом месте

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

Надеюсь, кто-то еще найдет это полезным!


Пример репозитория github: https://github.com/dennmat/flutter-connectiontest-example

Переключите режим полета в эмуляторе, чтобы увидеть результат

Полный пример, демонстрирующий слушателя интернет-соединения и его источника.

Кредит: связь и 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();
}

Я обнаружил, что простого использования пакета подключения было недостаточно, чтобы определить, доступен ли Интернет или нет. В Android он проверяет только наличие Wi-Fi или включение мобильных данных, но не проверяет наличие фактического подключения к Интернету. Во время моего тестирования даже без мобильного сигнала ConnectivityResult.mobile возвращал true.

В IOS мое тестирование показало, что подключаемый модуль подключения правильно определяет, есть ли подключение к Интернету, когда на телефоне нет сигнала, проблема была только в Android.

Решение, которое я нашел, заключалось в использовании пакета https://pub.dev/packages/data_connection_checker вместе с пакетом подключения. Это просто гарантирует наличие подключения к Интернету, отправляя запросы на несколько надежных адресов, тайм-аут по умолчанию для проверки составляет около 10 секунд.

Моя законченная функция isInternet выглядела примерно так:

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

В if (await DataConnectionChecker().hasConnection)часть одинакова как для мобильных, так и для Wi-Fi-соединений и, вероятно, должна быть перенесена в отдельную функцию. Я не сделал этого здесь, чтобы сделать его более читабельным.

Это мой первый ответ о переполнении стека, надеюсь, он кому-то поможет.

С помощью

dependencies:
  connectivity: ^0.4.2

что мы получили от ресурсов

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

Будущее для меня немного проблематично, мы должны реализовывать его каждый раз, как:

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

Итак, чтобы решить эту проблему, я создал класс, который принимает функцию с логическим параметром isNetworkPresent, например

methodName(bool isNetworkPresent){}

А сервисный класс

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

И использовать утилиту проверки соединения

  fetchPrefrence(bool isNetworkPresent) {
    if(isNetworkPresent){

    }else{

    }
  }

я буду использовать этот синтаксис

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

Я сделал базовый класс для состояния виджета

Использование вместо State<LoginPage> использование BaseState<LoginPage> тогда просто используйте логическую переменную isOnline

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

Сначала добавьте плагин подключения:

dependencies:
  connectivity: ^0.4.3+2

Затем добавьте класс 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 {
  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;
  }
}

Хочу добавить что-то к ответу Oren: вам действительно нужно добавить еще один улов, который будет перехватывать все другие исключения (просто для безопасности), ИЛИ просто удалить тип исключения полностью и использовать улов, который имеет дело со всеми исключениями:

Случай 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;
}

или даже проще...

Случай 2:


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

Хорошо, я прочитал почти все сообщения, и сообщение @dennmat мне наиболее полезно. хотя у меня это не сработало и тоже устарело. У меня обновление с обновленным флаттером connectivity пакет (т.е. connectivity_plus) и (чтобы проверить, есть ли фактическое подключение к Интернету для мобильных устройств и Wi-Fi).
После этого поста вы сможете постоянно прослушивать интернет-соединение.

1. Добавьте зависимости
a) connectivity_plus: ^1.0.6
b) data_connection_checker: ^0.3.4

2. Пользовательский класс, который обрабатывает все соединения.

      import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:data_connection_checker/data_connection_checker.dart'; 

class ConnectionUtil {
  //This creates the single instance by calling the `_internal` constructor specified below
  static final ConnectionUtil _singleton = new ConnectionUtil._internal();
  ConnectionUtil._internal();
  //This is what's used to retrieve the instance through the app
  static ConnectionUtil getInstance() => _singleton;
  //This tracks the current connection status
  bool hasConnection = false;
  //This is how we'll allow subscribing to connection changes
  StreamController connectionChangeController = StreamController();
  //flutter_connectivity
  final Connectivity _connectivity = Connectivity();
  void initialize() {
    _connectivity.onConnectivityChanged.listen(_connectionChange);
  }
  //flutter_connectivity's listener
  void _connectionChange(ConnectivityResult result) {
    hasInternetInternetConnection();
  }
  Stream get connectionChange => connectionChangeController.stream;
  Future<bool> hasInternetInternetConnection() async {
    bool previousConnection = hasConnection;
    var connectivityResult = await (Connectivity().checkConnectivity());
    //Check if device is just connect with mobile network or wifi
    if (connectivityResult == ConnectivityResult.mobile ||
        connectivityResult == ConnectivityResult.wifi) {
      //Check there is actual internet connection with a mobile network or wifi
      if (await DataConnectionChecker().hasConnection) {
        // Network data detected & internet connection confirmed.
        hasConnection = true;
      } else {
        // Network data detected but no internet connection found.
        hasConnection = false;
      }
    }
    // device has no mobile network and wifi connection at all
    else {
      hasConnection = false;
    }
    // The connection status changed send out an update to all listeners
    if (previousConnection != hasConnection) {
      connectionChangeController.add(hasConnection);
    }
    return hasConnection;
  }
}
  1. Проверяйте связь в любом месте и прислушивайтесь к изменениям.
      @override
  initState() {
    print('called');
    //Create instance
    ConnectionUtil connectionStatus = ConnectionUtil.getInstance();
    //Initialize
    connectionStatus.initialize();
    //Listen for connection change
    _connectionChangeStream = connectionStatus.connectionChange.listen((event) {
      print(event);
    });

    super.initState();
  }

Теперь проверьте журнал при переключении режима полета. вы должны получить журнал с истинным и ложным значениями.

Примечание: это не будет работать во флаттер-сети, если вы хотите заставить его работать, чем используйте dio или http плагин вместо data_connection_checker.

Пример проекта можно найти здесь . Спасибо

У меня возникла проблема с предлагаемыми решениями, используя lookup не всегда возвращает ожидаемое значение.

Это связано с кешированием DNS, значение вызова кэшируется и, если при следующей попытке выполнить правильный вызов, он возвращает кешированное значение. Конечно, это проблема здесь, поскольку это означает, что если вы потеряете соединение и позвонитеlookup он все равно может вернуть кешированное значение, как если бы у вас был Интернет, и, наоборот, если вы повторно подключите свой Интернет после lookup вернул ноль, он все равно вернет ноль на время кеширования, которое может составлять несколько минут, даже если у вас сейчас есть интернет.

TL;DR: lookupвозврат чего-либо не обязательно означает, что у вас есть Интернет, и отсутствие возврата не обязательно означает, что у вас нет Интернета. Это ненадежно.

Я реализовал следующее решение, вдохновившись data_connection_checker плагин:

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

Призыв к _checkInternetAccess занимает самое большее время timeoutдля завершения (здесь 3 секунды), и если мы сможем связаться с любым из DNS, он будет завершен, как только будет достигнут первый, не дожидаясь остальных (так как достижения одного достаточно, чтобы знать, что у вас есть Интернет). Все звонки_pingDns делаются параллельно.

Кажется, он хорошо работает в сети IPV4, и когда я не могу протестировать его в сети IPV6 (у меня нет доступа к одной), я думаю, что он все равно должен работать. Он также работает в сборках в режиме выпуска, но мне еще нужно отправить свое приложение в Apple, чтобы узнать, обнаружат ли они какие-либо проблемы с этим решением.

Он также должен работать в большинстве стран (включая Китай), если он не работает в одной из них, вы можете добавить DNS в список, доступный из вашей целевой страны.

После ответа @dennmatt я заметил, что InternetAddress.lookup может дать успешные результаты, даже если интернет-соединение отключено - я проверил его, подключившись со своего симулятора к домашнему Wi-Fi, а затем отключив кабель маршрутизатора. Я думаю, причина в том, что маршрутизатор кэширует результаты поиска домена, поэтому ему не нужно запрашивать DNS-серверы при каждом запросе поиска.

В любом случае, если вы используете Firestore, как я, вы можете заменить блок try-SocketException-catch пустой транзакцией и перехватить 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;
}

Также обратите внимание, что previousConnection устанавливается перед асинхронной интенет-проверкой, поэтому теоретически, если checkConnection() вызывается несколько раз за короткое время, может быть несколько hasConnection=true подряд или несколько hasConnection=false в ряд. Я не уверен, что @dennmatt сделал это нарочно или нет, но в нашем случае использования не было никаких побочных эффектов (setState был вызван только дважды с одинаковым значением).

Пакет подключения: не гарантирует фактическое подключение к Интернету (может быть просто подключение к Wi-Fi без доступа в Интернет).

Цитата из документации:

Обратите внимание, что на Android это не гарантирует подключение к Интернету. Например, приложение может иметь доступ к Wi-Fi, но это может быть VPN или Wi-Fi в отеле без доступа.

Если вам действительно нужно проверить подключение к Интернету www, лучшим выбором будет

https://pub.dev/packages/data_connection_checker

используйте Connectivity_widget: ^ 0.1.7

добавить зависимости:

      dependencies:
     connectivity_widget: ^0.1.7

добавить код:

                 ConnectivityWidget(
            builder: (context, isOnline) => Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    "${isOnline ? 'Connected' : 'Offline'}",
                    style: TextStyle(
                        fontSize: 30,
                        color: isOnline ? Colors.green : Colors.red),
                  ),
                ],
              ),
            ),
          )

при использовании во всем приложении (глобально)

      void main() => runApp(MaterialApp(
  title: 'Flutter Calendar',
  home: Scaffold(
    body: ConnectivityWidget(
      builder: (context, isOnline) => MyApp(),
    ),
  ),
));

пример (полный код)

      import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_applicationdemo08/splashScreen.dart';
import 'package:image_picker/image_picker.dart';
import 'package:connectivity_widget/connectivity_widget.dart';

void main() => runApp(MaterialApp(
      title: 'Flutter Calendar',
      home: Scaffold(
        body: ConnectivityWidget(
          builder: (context, isOnline) => MyApp(),
        ),
      ),
    ));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        fontFamily: "intel",
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Splash(),
    );
  }
}

ВЫХОД:

В конце концов (хотя и неохотно) я остановился на решении, данном @abernee в предыдущем ответе на этот вопрос. Я всегда стараюсь использовать как можно меньше внешних пакетов в своих проектах - поскольку я знаю, что внешние пакеты - единственные [потенциальные] точки отказа в создаваемом мной программном обеспечении. Поэтому для меня было непросто создать ссылку на ДВА внешних пакета только для такой простой реализации.

Тем не менее, я взял код Аберни и изменил его, чтобы сделать его более компактным и разумным. Под разумным я имею в виду, что он потребляет мощность пакета Connectivity в своей функции, но затем растрачивает ее внутри, не возвращая наиболее ценные выходные данные из этого пакета (то есть идентификацию сети). Итак, вот модифицированная версия решения 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;
  }

}

Затем вы можете использовать эту статическую функцию с помощью простого вызова из любого места вашего кода следующим образом:

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

Жалко, что вам нужно установить ссылку на ДВА ВНЕШНИХ ПАКЕТА, чтобы получить эту базовую функциональность в вашем проекте Flutter, но я думаю, что на данный момент это лучшее, что у нас есть. На самом деле я предпочитаю пакет Data Connection Checker пакету Connectivity, но (на момент публикации этого сообщения) в первом отсутствовала эта очень важная функция сетевой идентификации, которую я требую от пакета Connectivity. Это причина того, что я отказался от этого подхода [временно].

Я написал пакет для проверки активного интернет-соединения и соответствующего отображения виджета.

flutter_no_internet_widget

Пример:

      InternetWidget(
 online: Text('Online'),
 offline: Text('Offline),
);

В соответствии с состоянием сети будут отображаться соответствующие виджеты. Если у вас есть активное подключение к Интернету, появится онлайн-виджет.

Все самое тяжелое делается пакетом, и все, что вам нужно сделать, это предоставить онлайн и оффлайн виджеты. При желании вы можете предоставить загрузочный виджет и URL-адрес поиска.

Обсуждение, PR или предложения приветствуются.

Вы можете использовать этот пакет https://pub.dev/packages/flutter_network_connectivity.

Под капотом он использует NetworkCapabilities на Android и NetworkMonitor на iOS и прослушивает изменения подключения и выполняет эхо-запросы для проверки доступности Интернета. Вы также можете настроить поиск доступности Интернета через определенные промежутки времени.

Добавьте в свой pubspec.yaml

      flutter_network_connectivity: ^0.0.6

Создать объект

      FlutterNetworkConnectivity flutterNetworkConnectivity =
    FlutterNetworkConnectivity(
      isContinousLookUp: true,  // optional, false if you cont want continous lookup
      lookUpDuration: const Duration(seconds: 5),  // optional, to override default lookup duration
      lookUpUrl: 'example.com',  // optional, to override default lookup url
);

и вы можете использовать его методы для непрерывной проверки сетевого подключения или вызова для проверки текущего состояния.

      _flutterNetworkConnectivity.getInternetAvailabilityStream().listen((isInternetAvailable) {
  // do something
});

и зарегистрируйте слушателя

      await _flutterNetworkConnectivity.registerAvailabilityListener();

проверить статус вызова

      bool _isNetworkConnectedOnCall = await _flutterNetworkConnectivity.isInternetConnectionAvailable();

Вот мое решение. Он проверяет подключение к Интернету, а также подключение к данным. Надеюсь, вам понравится.

Прежде всего добавьте зависимости в свой pubsec.yaml
dependencies:        
    data_connection_checker:
И вот главный дарт моего решения
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"),
        ),
      ),
    );
  }
}

Чтобы проверить, есть ли у вас доступ в Интернет или нет, даже если вы подключены к Wi-Fi, используйте функцию ниже.

      Future<bool> checkInternetStatus() async {
    try {
      final url = Uri.https('google.com');
      var response = await http.get(url);
      if (response.statusCode == 200) {
        return true;
      } else {
        return false;
      }
    } catch (e) {
      return false;
    }
  }

также добавьте зависимость http: ^0.13.5, затем импортируйте «package:http/http.dart» как http;

На основе этого ответа /questions/23175967/proverte-dostupno-li-podklyuchenie-k-internetu-v-prilozhenii-flutter/58645571#58645571

Если вы использовали нулевую безопасность dart, вы получите сообщение об ошибке, поэтому вы можете обновить зависимости data_connection_checker: ^0.3.4 до internet_connection_checker: ^0.0.1+2

и вы можете использовать этот код

      import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';

class ConnectionUtil {
  static final ConnectionUtil _singleton = new ConnectionUtil._internal();
  ConnectionUtil._internal();

  static ConnectionUtil getInstance() => _singleton;

  bool hasConnection = false;

  StreamController connectionChangeController = StreamController();

  final Connectivity _connectivity = Connectivity();
  void initialize() {
    _connectivity.onConnectivityChanged.listen(_connectionChange);
  }

  void _connectionChange(ConnectivityResult result) {
    _hasInternetInternetConnection();
  }

  Stream get connectionChange => connectionChangeController.stream;
  Future<bool> _hasInternetInternetConnection() async {
    bool previousConnection = hasConnection;
    var connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult == ConnectivityResult.mobile || connectivityResult == ConnectivityResult.wifi) {
      // this is the different
      if (await InternetConnectionChecker().hasConnection) {
        hasConnection = true;
      } else {
        hasConnection = false;
      }
    } else {
      hasConnection = false;
    }

    if (previousConnection != hasConnection) {
      connectionChangeController.add(hasConnection);
    }
    return hasConnection;
  }
}

и в виджете с отслеживанием состояния вы можете реализовать этот код

        bool hasInterNetConnection = false;

  @override
  initState() {
    ConnectionUtil connectionStatus = ConnectionUtil.getInstance();
    connectionStatus.initialize();
    // This code to handle if within 2 seconds there is no connection
    // then the connection will return false as default value
    Timer.periodic(Duration(seconds: 2), (timer) {
      setState(() {
        hasInterNetConnection = false;
      });
    });
    connectionStatus.connectionChange.listen(connectionChanged);

    super.initState();
  }

  void connectionChanged(dynamic hasConnection) {
    setState(() {
      hasInterNetConnection = hasConnection;
    });
  }
      import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:app_settings/app_settings.dart';
import 'package:connectivity/connectivity.dart';

class InternetConnect extends StatefulWidget {
  @override
  InternetConnectState createState() => InternetConnectState();
}

class InternetConnectState extends State<InternetConnect> {
  ConnectivityResult previous;
  bool dialogshown = false;
  StreamSubscription connectivitySubscription;

  Future<bool> checkinternet() async {
    try {
      final result = await InternetAddress.lookup('google.com');
      if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
        return Future.value(true);
      }
    } on SocketException catch (_) {
      return Future.value(false);
    }
  }

  void checkInternetConnect(BuildContext context) {
    connectivitySubscription = Connectivity()
        .onConnectivityChanged
        .listen((ConnectivityResult connresult) {
      if (connresult == ConnectivityResult.none) {
        dialogshown = true;
        showDialog(
            context: context, barrierDismissible: false, child: alertDialog());
      } else if (previous == ConnectivityResult.none) {
        checkinternet().then((result) {
          if (result == true) {
            if (dialogshown == true) {
              dialogshown = false;
              Navigator.pop(context);
            }
          }
        });
      }

      previous = connresult;
    });
  }

  AlertDialog alertDialog() {
    return AlertDialog(
      title: Text('ERROR'),
      content: Text("No Internet Detected."),
      actions: <Widget>[
        FlatButton(
          // method to exit application programitacally

          onPressed: () {
            AppSettings.openWIFISettings();
          },
          child: Text("Settings"),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

    and you can use this method in init of any class

@override
void initState() {
  // TODO: implement initState
  InternetConnectState().checkInternetConnect(context);
  super.initState();
}

Я использовал пакет data_connection_checker для проверки доступа в Интернет, даже если соединение доступно через Wi-Fi или мобильное устройство, оно работает хорошо: вот код для проверки соединения:

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

ознакомьтесь с пакетом, если вам нужна дополнительная информация.Пакет проверки подключения к данным

Просто пытаюсь упростить код с помощью пакета подключения во 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
}

Поздний ответ, но используйте этот пакет, чтобы проверить. Имя пакета: data_connection_checker

в вашем файле pubspec.yuml:

dependencies:
    data_connection_checker: ^0.3.4

создайте файл с именем connection.dart или любым другим именем. импортировать пакет:

import 'package:data_connection_checker/data_connection_checker.dart';

проверьте, есть ли подключение к интернету:

print(await DataConnectionChecker().hasConnection);

У меня возникла проблема с принятым ответом, но, похоже, это решает ответ для других. Мне нужно решение, которое может получать ответ от используемого URL-адреса, поэтому я подумал, что http отлично подойдет для этой функции, и для этого я нашел этот ответ действительно полезным. Как проверить подключение к Интернету с помощью HTTP-запросов (Flutter/Dart)?

окончательный результат ConnectivityResult = await Connectivity().checkConnectivity();

      if (result == ConnectivityResult.wifi) {
  print('Connected to a Wi-Fi network');
} else if (result == ConnectivityResult.mobile) {
  print('Connected to a mobile network');
} else {
  print('Not connected to any network');
}

Используйте пакет наблюдать_интернет_подключение .

Доступные функции

  1. Проверьте, подключено ли устройство к Интернету
        final hasInternet = await InternetConnectivity().hasInternetConnection;
  if (hasInternet) {
    //You are connected to the internet
  } else {
    //"No internet connection
  }
  1. Слушайте изменения интернет-соединения через поток
        final subscription =
      InternetConnectivity().observeInternetConnection.listen((bool hasInternetAccess) {
        if(!hasInternetAccess){
          showToast('No Internet Connection');
        }
      });

   await Future.delayed(const Duration(seconds: 10 ));
   subscription.cancel();
  1. Использовать InternetConnectivityListenerдля прослушивания изменений подключения к Интернету внутри флаттер-виджета
          return InternetConnectivityListener(
      connectivityListener: (BuildContext context, bool hasInternetAccess) {
        if (hasInternetAccess) {
          context.showBanner('You are back Online!', color: Colors.green);
        } else {
          context.showBanner('No internet connection', color: Colors.red);
        }
      },
      child: Scaffold(
        body: Container(),
      ),
    );
  1. Использовать InternetConnectivityBuilderдля создания виджетов с информацией о подключении к Интернету
          return InternetConnectivityBuilder(
      connectivityBuilder: (BuildContext context, bool hasInternetAccess, Widget? child) { 
        if(hasInternetAccess) {
          return OnlineWidget();
        } else {
          return OfflineWidget();
        }
      },
      child: ChildWidget(),
    );

Основная проблема с пакетом подключения заключается в том, что он срабатывает только в том случае, если интерфейс полностью выходит из строя. Поскольку меня на самом деле интересует не то, как пользователь подключен, а, скорее, ЕСЛИ он подключен, я придумал это решение, которое можно обернуть вокруг любого другого виджета, требующего доступа в Интернет.

      import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';

class ConnectivityWidget extends StatefulWidget {
  const ConnectivityWidget({super.key, required this.child});
  final Widget child;

  @override
  State<ConnectivityWidget> createState() => _ConnectivityWidgetState();
}

class _ConnectivityWidgetState extends State<ConnectivityWidget> {
  final myConnectivity = MyConnectivity.instance;
  bool? isOnline;
  @override
  void initState() {
    super.initState();
    myConnectivity.continueslyCheckInternetConnection().listen((result) {
      setState(() => isOnline = result);
    });
  }

  @override
  Widget build(BuildContext context) {
    if (isOnline == null) {
      return const Scaffold(
        body: Center(child: Text('Checking internet connection...')),
      );
    }
    if (isOnline == false) {
      return const Scaffold(
        body: Center(child: Text('No Internet connection.', style: TextStyle(color: Colors.red))),
      );
    }
    return widget.child;
  }

  @override
  void dispose() {
    debugPrint('NEVER SHOULD HAPPEN: Disposing MainApp...');
    myConnectivity.disposeStream();
    super.dispose();
  }
}

class MyConnectivity {
  MyConnectivity._();

  static final _instance = MyConnectivity._();
  static MyConnectivity get instance => _instance;
  final _controller = StreamController<bool>.broadcast();

  Stream<bool> continueslyCheckInternetConnection() {
    Timer.periodic(const Duration(seconds: 1), (timer) async {
      bool isOnline = false;
      try {
        final result = await InternetAddress.lookup('www.google.com');
        isOnline = result.isNotEmpty && result[0].rawAddress.isNotEmpty;
      } on SocketException catch (_) {
        isOnline = false;
      }
      final timestamp = DateTime.timestamp().millisecondsSinceEpoch;
      debugPrint('$timestamp - Internet:$isOnline');
      _controller.add(isOnline);
    });
    return _controller.stream;
  }

  void disposeStream() => _controller.close();
}

Для меня я просто создаю отдельные данные в Firebase и использую future builder для ожидания данных. Здесь, вот так, вы можете проверить, не слишком ли медленное соединение, чтобы данные загружались:

      FutureBuilder(
    future: _getImage(context),
    builder: (context, snapshot) {
      switch (snapshot.connectionState) {
        case ConnectionState.none:
          return Text('Press button to start.');
        case ConnectionState.active:
        case ConnectionState.waiting:
          return Container(
              height:
                  MediaQuery.of(context).size.height / 1.25,
              width:
                  MediaQuery.of(context).size.width / 1.25,
              child: Loading());
        case ConnectionState.done:
          if (snapshot.hasData) {
            return snapshot.data;
          } else {
            return FlatButton(
              onPressed: () {
                Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) =>
                            ProfilePage()));
              },
              child: Icon(
                Icons.add_a_photo,
                size: 50,
              ),
            );
          }
        // You can reach your snapshot.data['url'] in here
      }
      return null;
    },
  ),

Сегодня 2023 год. Вот решение, которое у меня есть.

      try {
    final dio = Dio();
    final response = await dio.get('https://www.google.com');
    if (response.statusCode == 200) {
      internetAccessible = "Ready";
    } else {
      internetAccessible = "Not Ready";
    }
  } catch (_) {
    internetAccessible = "Not Ready";
  }

Кажется, это работает на моем планшете Android с отключенным WLAN и подключением к Wi-Fi, у которого нет Интернета.

Поскольку это старый вопрос, за последние 5 лет многое изменилось, и он больше не работает (по крайней мере, для меня), как я пробовал сегодня.

К счастью, я нашел https://pub.dev/packages/internet_connection_checker , который прекрасно работает для проверки подключения к Интернету.

Как говорит автор Назначение пакета:

Причина существования этого пакета заключается в том, чтоconnectivity_plusПакет не может достоверно определить, действительно ли доступно соединение для передачи данных. Дополнительная информация на его странице здесь: https://pub.dev/packages/connectivity_plus .

Поэтому рекомендуем использоватьinternet_connection_checkerи код ниже должен работать:

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

Лучше всего то, что это все дротики, на которых основано трепетание.

Плагин подключения указывает в своих документах, что он предоставляет информацию только при наличии сетевого подключения, но не в том случае, если сеть подключена к Интернету. Используйте приведенный ниже код и не забудьте использовать «.timeout()», потому что вы можете застрять навсегда, используя «ожидание».

      import 'dart:io';

Future<bool> isConnected() async {
  try {
    List<InternetAddress> result = await InternetAddress.lookup('example.com')
        .timeout(Duration(seconds: 5));

    //
    if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
      return true;
    }
    //
    else {
      return false;
    }
  } on SocketException catch (_) {
    return false;
  }
}
Другие вопросы по тегам