У меня возникла проблема с предлагаемыми решениями, использование 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 в список, доступный из вашей целевой страны.