Saya memiliki masalah dengan solusi yang diusulkan, menggunakan lookup
tidak selalu mengembalikan nilai yang diharapkan.
Ini karena DNS caching, nilai panggilan di-cache dan bukannya melakukan panggilan yang benar pada percobaan berikutnya, ia mengembalikan nilai yang di-cache. Tentu saja ini menjadi masalah di sini karena artinya jika Anda kehilangan konektivitas dan memanggilnya lookup
masih dapat mengembalikan nilai yang di-cache seolah-olah Anda memiliki internet, dan sebaliknya, jika Anda menyambungkan kembali internet Anda setelah lookup
mengembalikan nol, itu akan tetap mengembalikan nol selama durasi cache, yang dapat memakan waktu beberapa menit, meskipun Anda memiliki internet sekarang.
TL; DR: lookup
mengembalikan sesuatu tidak selalu berarti Anda memiliki internet, dan tidak mengembalikan apa pun tidak berarti Anda tidak memiliki internet. Itu tidak bisa diandalkan.
Saya menerapkan solusi berikut dengan mengambil inspirasi dari 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;
}
Panggilan untuk _checkInternetAccess
memakan waktu paling lama timeout
hingga selesai (3 detik di sini), dan jika kita dapat mencapai salah satu DNS, itu akan selesai segera setelah yang pertama tercapai, tanpa menunggu yang lain (karena mencapai satu sudah cukup untuk tahu Anda memiliki internet). Semua panggilan ke _pingDns
dilakukan secara paralel.
Tampaknya berfungsi dengan baik di jaringan IPV4, dan ketika saya tidak dapat mengujinya di jaringan IPV6 (saya tidak memiliki akses ke salah satunya), saya pikir itu masih harus berfungsi. Ini juga berfungsi pada build mode rilis, tetapi saya belum harus mengirimkan aplikasi saya ke Apple untuk melihat apakah mereka menemukan masalah dengan solusi ini.
Ini juga harus berfungsi di sebagian besar negara (termasuk Cina), jika tidak berfungsi di salah satu, Anda dapat menambahkan DNS ke daftar yang dapat diakses dari negara target Anda.