我对建议的解决方案有疑问,使用lookup
并不总是返回预期值。
这是由于 DNS 缓存,调用的值被缓存,而不是在下一次尝试时执行正确的调用,它会返回缓存的值。当然这是一个问题,因为这意味着如果您失去连接并调用lookup
它仍然可以返回缓存值,就像您有互联网一样,相反,如果您在lookup
返回 null 后重新连接互联网,它仍然会在持续时间内返回 null缓存,这可能是几分钟,即使你现在有互联网。
TL;DR:lookup
返回一些东西并不一定意味着你有互联网,它不返回任何东西并不一定意味着你没有互联网。它不可靠。
data_connection_checker
我从插件中获得灵感,实现了以下解决方案:
/// If any of the pings returns true then you have internet (for sure). If none do, you probably don't.
Future<bool> _checkInternetAccess() {
/// We use a mix of IPV4 and IPV6 here in case some networks only accept one of the types.
/// Only tested with an IPV4 only network so far (I don't have access to an IPV6 network).
final List<InternetAddress> dnss = [
InternetAddress('8.8.8.8', type: InternetAddressType.IPv4), // Google
InternetAddress('2001:4860:4860::8888', type: InternetAddressType.IPv6), // Google
InternetAddress('1.1.1.1', type: InternetAddressType.IPv4), // CloudFlare
InternetAddress('2606:4700:4700::1111', type: InternetAddressType.IPv6), // CloudFlare
InternetAddress('208.67.222.222', type: InternetAddressType.IPv4), // OpenDNS
InternetAddress('2620:0:ccc::2', type: InternetAddressType.IPv6), // OpenDNS
InternetAddress('180.76.76.76', type: InternetAddressType.IPv4), // Baidu
InternetAddress('2400:da00::6666', type: InternetAddressType.IPv6), // Baidu
];
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 秒才能完成(此处为 3 秒),如果我们可以到达任何 DNS,它将在到达第一个 DNS 后立即完成,而无需等待其他(因为到达一个足以知道你有互联网)。所有的调用_pingDns
都是并行完成的。
它似乎在 IPV4 网络上运行良好,当我无法在 IPV6 网络上测试它时(我无权访问它),我认为它应该仍然可以工作。它也适用于发布模式构建,但我还必须将我的应用程序提交给 Apple 以查看他们是否发现此解决方案有任何问题。
它也应该适用于大多数国家(包括中国),如果它在一个国家/地区不起作用,您可以将 DNS 添加到可从您的目标国家/地区访问的列表中。