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