feat(fl_query_connectivity_plus_adapter): lookup based offline detection
This commit is contained in:
@@ -111,21 +111,21 @@ packages:
|
|||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "1.0.0-alpha.4"
|
version: "1.0.0-alpha.5"
|
||||||
fl_query_connectivity_plus_adapter:
|
fl_query_connectivity_plus_adapter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "../../fl_query_connectivity_plus_adapter"
|
path: "../../fl_query_connectivity_plus_adapter"
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "0.1.0-alpha.3"
|
version: "0.1.0-alpha.4"
|
||||||
fl_query_devtools:
|
fl_query_devtools:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "../../fl_query_devtools"
|
path: "../../fl_query_devtools"
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "0.1.0-alpha.2"
|
version: "0.1.0-alpha.3"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:fl_query_connectivity_plus_adapter/lookups/connection_lookup_io.dart'
|
||||||
|
if (dart.library.html) 'package:fl_query_connectivity_plus_adapter/lookups/connection_lookup_web.dart';
|
||||||
|
|
||||||
|
abstract class ConnectionLookup {
|
||||||
|
Future<bool> doesConnectTo(String address);
|
||||||
|
Future<bool> isVpnActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
class InternetConnectivityChecker
|
||||||
|
with WidgetsBindingObserver, ConnectionLookupMixin {
|
||||||
|
final StreamController<bool> controller;
|
||||||
|
|
||||||
|
bool _wasConnected = true;
|
||||||
|
|
||||||
|
bool get isAppPaused =>
|
||||||
|
WidgetsBinding.instance.lifecycleState == AppLifecycleState.paused;
|
||||||
|
|
||||||
|
InternetConnectivityChecker(Duration duration)
|
||||||
|
: controller = StreamController<bool>.broadcast() {
|
||||||
|
Timer.periodic(duration, (timer) async {
|
||||||
|
if (isAppPaused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await hasConnection();
|
||||||
|
});
|
||||||
|
Connectivity().onConnectivityChanged.listen((event) async {
|
||||||
|
if (isAppPaused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await hasConnection();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
didChangeAppLifecycleState(AppLifecycleState state) async {
|
||||||
|
if (state == AppLifecycleState.resumed) {
|
||||||
|
await hasConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> hasConnection() async {
|
||||||
|
final connectivityResult = await (Connectivity().checkConnectivity());
|
||||||
|
final hasNetwork = [
|
||||||
|
ConnectivityResult.mobile,
|
||||||
|
ConnectivityResult.wifi,
|
||||||
|
ConnectivityResult.ethernet,
|
||||||
|
].contains(connectivityResult);
|
||||||
|
|
||||||
|
final isVpn =
|
||||||
|
connectivityResult == ConnectivityResult.vpn || await isVpnActive();
|
||||||
|
|
||||||
|
final connected = hasNetwork
|
||||||
|
? kIsWeb
|
||||||
|
? await doesConnectTo('/favicon.ico') ||
|
||||||
|
await doesConnectTo('/favicon.png') ||
|
||||||
|
await doesConnectTo('/favicon.gif')
|
||||||
|
: await doesConnectTo('google.com') ||
|
||||||
|
await doesConnectTo('www.baidu.com')
|
||||||
|
: isVpn;
|
||||||
|
|
||||||
|
if (connected != _wasConnected) {
|
||||||
|
_wasConnected = connected;
|
||||||
|
controller.add(connected);
|
||||||
|
}
|
||||||
|
return connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<bool> get onConnectionChanged => controller.stream;
|
||||||
|
}
|
||||||
+8
-20
@@ -1,32 +1,20 @@
|
|||||||
library fl_query_connectivity_plus_adapter;
|
library fl_query_connectivity_plus_adapter;
|
||||||
|
|
||||||
import 'package:fl_query/fl_query.dart';
|
import 'package:fl_query/fl_query.dart';
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:fl_query_connectivity_plus_adapter/connection_checker.dart';
|
||||||
|
|
||||||
/// A [ConnectivityAdapter] that uses the `connectivity_plus` package.
|
/// A [ConnectivityAdapter] that uses the `connectivity_plus` package.
|
||||||
class FlQueryConnectivityPlusAdapter extends ConnectivityAdapter {
|
class FlQueryConnectivityPlusAdapter extends ConnectivityAdapter {
|
||||||
|
final InternetConnectivityChecker _adapter;
|
||||||
|
FlQueryConnectivityPlusAdapter({
|
||||||
|
Duration pollingDuration = const Duration(minutes: 5),
|
||||||
|
}) : _adapter = InternetConnectivityChecker(pollingDuration);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> get isConnected async {
|
Future<bool> get isConnected async {
|
||||||
final connection = await Connectivity().checkConnectivity();
|
return await _adapter.hasConnection();
|
||||||
|
|
||||||
switch (connection) {
|
|
||||||
case ConnectivityResult.bluetooth:
|
|
||||||
case ConnectivityResult.none:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<bool> get onConnectivityChanged =>
|
Stream<bool> get onConnectivityChanged => _adapter.onConnectionChanged;
|
||||||
Connectivity().onConnectivityChanged.map((event) {
|
|
||||||
switch (event) {
|
|
||||||
case ConnectivityResult.bluetooth:
|
|
||||||
case ConnectivityResult.none:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:fl_query_connectivity_plus_adapter/connection_checker.dart';
|
||||||
|
|
||||||
|
mixin ConnectionLookupMixin implements ConnectionLookup {
|
||||||
|
@override
|
||||||
|
Future<bool> doesConnectTo(String address) async {
|
||||||
|
try {
|
||||||
|
final result = await InternetAddress.lookup(address);
|
||||||
|
return result.isNotEmpty && result[0].rawAddress.isNotEmpty;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const _vpnNames = [
|
||||||
|
'tun',
|
||||||
|
'tap',
|
||||||
|
'ppp',
|
||||||
|
'pptp',
|
||||||
|
'l2tp',
|
||||||
|
'ipsec',
|
||||||
|
'vpn',
|
||||||
|
'wireguard',
|
||||||
|
'openvpn',
|
||||||
|
'softether',
|
||||||
|
'proton',
|
||||||
|
'strongswan',
|
||||||
|
'cisco',
|
||||||
|
'forticlient',
|
||||||
|
'fortinet',
|
||||||
|
'hideme',
|
||||||
|
'hidemy',
|
||||||
|
'hideman',
|
||||||
|
'hidester',
|
||||||
|
'lightway',
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> isVpnActive() async {
|
||||||
|
final interfaces = await NetworkInterface.list(
|
||||||
|
includeLoopback: false,
|
||||||
|
type: InternetAddressType.any,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (interfaces.isEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return interfaces.any(
|
||||||
|
(interface) =>
|
||||||
|
_vpnNames.any((name) => interface.name.toLowerCase().contains(name)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import 'dart:html';
|
||||||
|
import 'package:fl_query_connectivity_plus_adapter/connection_checker.dart';
|
||||||
|
|
||||||
|
mixin ConnectionLookupMixin implements ConnectionLookup {
|
||||||
|
@override
|
||||||
|
Future<bool> doesConnectTo(String address) async {
|
||||||
|
try {
|
||||||
|
final url = address.startsWith("http") || address.startsWith("/")
|
||||||
|
? address
|
||||||
|
: "https://$address";
|
||||||
|
final request = await HttpRequest.request(
|
||||||
|
url,
|
||||||
|
requestHeaders: {
|
||||||
|
'Cache-Control': 'no-cache',
|
||||||
|
'Pragma': 'no-cache',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return (request.status ?? 0) < 400;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> isVpnActive() {
|
||||||
|
return Future.value(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user