提案された解決策に問題がありました。使用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のいずれかに到達できる場合は、最初のDNSに到達するとすぐに、他のDNSを待たずに完了します(1つに到達するだけで十分です)。あなたがインターネットを持っていることを知っています)。へのすべての呼び出し_pingDns
は並行して行われます。
IPV4ネットワークではうまく機能しているようですが、IPV6ネットワークでテストできない場合(アクセスできない場合)でも機能するはずです。リリースモードのビルドでも機能しますが、このソリューションに問題がないかどうかを確認するために、アプリをAppleに送信する必要があります。
また、ほとんどの国(中国を含む)でも機能するはずです。機能しない場合は、ターゲット国からアクセスできるDNSをリストに追加できます。