Tive um problema com as soluções propostas, lookup
nem sempre usar retorna o valor esperado.
Isso ocorre devido ao cache DNS, o valor da chamada é armazenado em cache e, em vez de fazer uma chamada adequada na próxima tentativa, ele retorna o valor armazenado em cache. Claro que isso é um problema aqui, pois significa que se você perder a conectividade e ligar para lookup
ele, ainda poderá retornar o valor em cache como se você tivesse internet e, inversamente, se você reconectar sua internet depoislookup
retornar nulo, ele ainda retornará nulo durante o cache, que pode demorar alguns minutos, mesmo se você tiver internet agora.
TL; DR: lookup
devolver algo não significa necessariamente que você tenha internet, e não devolver nada não significa necessariamente que você não tem internet. Não é confiável.
Implementei a seguinte solução inspirando-me no data_connection_checker
plugin:
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;
}
A chamada para _checkInternetAccess
leva no máximo uma duração de timeout
para ser concluída (3 segundos aqui), e se conseguirmos alcançar qualquer um dos DNS ela será concluída assim que o primeiro for alcançado, sem esperar pelos outros (pois chegar a um é suficiente para sabe que tem internet). Todas as chamadas para _pingDns
são feitas em paralelo.
Parece funcionar bem em uma rede IPV4, e quando não consigo testá-lo em uma rede IPV6 (não tenho acesso a uma), acho que ainda deve funcionar. Ele também funciona em compilações no modo de lançamento, mas ainda tenho que enviar meu aplicativo para a Apple para ver se eles encontram algum problema com esta solução.
Ele também deve funcionar na maioria dos países (incluindo a China). Se não funcionar em um deles, você pode adicionar um DNS à lista que pode ser acessada em seu país de destino.