Проверьте, доступно ли подключение к Интернету в приложении 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;
}
}
- Проверяйте связь в любом месте и прислушивайтесь к изменениям.
@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, лучшим выбором будет
используйте 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. Это причина того, что я отказался от этого подхода [временно].
Я написал пакет для проверки активного интернет-соединения и соответствующего отображения виджета.
Пример:
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.yamldependencies:
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');
}
Используйте пакет наблюдать_интернет_подключение .
Доступные функции
- Проверьте, подключено ли устройство к Интернету
final hasInternet = await InternetConnectivity().hasInternetConnection;
if (hasInternet) {
//You are connected to the internet
} else {
//"No internet connection
}
- Слушайте изменения интернет-соединения через поток
final subscription =
InternetConnectivity().observeInternetConnection.listen((bool hasInternetAccess) {
if(!hasInternetAccess){
showToast('No Internet Connection');
}
});
await Future.delayed(const Duration(seconds: 10 ));
subscription.cancel();
- Использовать
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(),
),
);
- Использовать
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;
}
}