У меня возникла проблема с предлагаемыми решениями, использование lookup
не всегда возвращает ожидаемое значение.
Это связано с кешированием DNS, значение вызова кэшируется и, если при следующей попытке выполнить правильный вызов, он возвращает кешированное значение. Конечно, это проблема здесь, так как это означает, что если вы потеряете подключение и вызовете lookup
его, он все равно может вернуть кешированное значение, как если бы у вас был Интернет, и, наоборот, если вы повторно подключите свой Интернет после lookup
возврата null, он все равно будет возвращать null на время кеш, что может занять несколько минут, даже если у вас сейчас есть Интернет.
TL; DR: lookup
возврат чего-либо не обязательно означает, что у вас есть Интернет, и отсутствие возврата не обязательно означает, что у вас нет Интернета. Это ненадежно.
Я реализовал следующее решение, вдохновившись data_connection_checker
плагином:
Future<bool> _checkInternetAccess() {
final List<InternetAddress> dnss = [
InternetAddress('8.8.8.8', type: InternetAddressType.IPv4),
InternetAddress('2001:4860:4860::8888', type: InternetAddressType.IPv6),
InternetAddress('1.1.1.1', type: InternetAddressType.IPv4),
InternetAddress('2606:4700:4700::1111', type: InternetAddressType.IPv6),
InternetAddress('208.67.222.222', type: InternetAddressType.IPv4),
InternetAddress('2620:0:ccc::2', type: InternetAddressType.IPv6),
InternetAddress('180.76.76.76', type: InternetAddressType.IPv4),
InternetAddress('2400:da00::6666', type: InternetAddressType.IPv6),
];
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 в список, доступный из вашей целевой страны.