Ich hatte ein Problem mit den vorgeschlagenen Lösungen. Die Verwendung lookup
gibt nicht immer den erwarteten Wert zurück.
Dies ist auf das DNS-Caching zurückzuführen. Der Wert des Anrufs wird zwischengespeichert, und anstatt beim nächsten Versuch einen ordnungsgemäßen Anruf auszuführen, wird der zwischengespeicherte Wert zurückgegeben. Dies ist hier natürlich ein Problem, da es bedeutet, dass bei einem Verbindungsverlust und einem Anruf lookup
der zwischengespeicherte Wert immer noch zurückgegeben werden kann, als ob Sie Internet hätten. Wenn Sie Ihr Internet nach der lookup
Rückgabe von null erneut verbinden, wird für die Dauer des Vorgangs immer noch null zurückgegeben Cache, der einige Minuten dauern kann, selbst wenn Sie jetzt über Internet verfügen.
TL; DR: lookup
Etwas zurückzugeben bedeutet nicht unbedingt, dass Sie Internet haben, und etwas zurückzugeben bedeutet nicht unbedingt, dass Sie kein Internet haben. Es ist nicht zuverlässig.
Ich habe die folgende Lösung implementiert, indem ich mich vom data_connection_checker
Plugin inspirieren ließ :
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;
}
Der Anruf _checkInternetAccess
dauert höchstens timeout
3 Sekunden (hier 3 Sekunden). Wenn wir einen der DNS erreichen können, wird er abgeschlossen, sobald der erste erreicht ist, ohne auf die anderen zu warten (da das Erreichen eines Anrufs ausreicht, um einen zu erreichen weiß, dass Sie Internet haben). Alle Anrufe _pingDns
werden parallel getätigt.
Es scheint in einem IPV4-Netzwerk gut zu funktionieren, und wenn ich es in einem IPV6-Netzwerk nicht testen kann (ich habe keinen Zugriff auf eines), denke ich, dass es immer noch funktionieren sollte. Es funktioniert auch bei Builds im Release-Modus, aber ich muss meine App noch bei Apple einreichen, um festzustellen, ob Probleme mit dieser Lösung auftreten.
Es sollte auch in den meisten Ländern (einschließlich China) funktionieren. Wenn es in einem nicht funktioniert, können Sie der Liste, auf die von Ihrem Zielland aus zugegriffen werden kann, einen DNS hinzufügen.