Ris*_*esh 35 dart flutter flutter-plugin
我有一个网络电话要执行.但在此之前,我需要检查设备是否具有互联网连接.
这是我到目前为止所做的:
var connectivityResult = new Connectivity().checkConnectivity();// User defined class
if (connectivityResult == ConnectivityResult.mobile ||
connectivityResult == ConnectivityResult.wifi) {*/
this.getData();
} else {
neverSatisfied();
}
Run Code Online (Sandbox Code Playgroud)
以上方法不起作用.
Gün*_*uer 71
该__CODE__插件在其文档中声明,它仅在存在网络连接时提供信息,但如果网络连接到Internet则不提供
请注意,在Android上,这并不保证与Internet的连接.例如,该应用程序可能具有WiFi访问权限,但它可能是VPN或无法访问的酒店WiFi.
您可以使用
import 'dart:io';
...
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
print('connected');
}
} on SocketException catch (_) {
print('not connected');
}
Run Code Online (Sandbox Code Playgroud)
abe*_*nee 32
我发现仅使用连接包不足以判断互联网是否可用。在 Android 中,它只检查是否有 WIFI 或移动数据是否打开,它不会检查实际的互联网连接。在我的测试过程中,即使没有移动信号 ConnectivityResult.mobile 也会返回 true。
对于 IOS,我的测试发现,当手机没有信号时,连接插件确实可以正确检测到是否有互联网连接,问题仅在于 Android。
我找到的解决方案是将data_connection_checker包与连接包一起使用。这只是通过向几个可靠地址发出请求来确保有互联网连接,检查的默认超时时间约为 10 秒。
我完成的 isInternet 函数看起来有点像这样:
Future<bool> isInternet() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
// I am connected to a mobile network, make sure there is actually a net connection.
if (await DataConnectionChecker().hasConnection) {
// Mobile data detected & internet connection confirmed.
return true;
} else {
// Mobile data detected but no internet connection found.
return false;
}
} else if (connectivityResult == ConnectivityResult.wifi) {
// I am connected to a WIFI network, make sure there is actually a net connection.
if (await DataConnectionChecker().hasConnection) {
// Wifi detected & internet connection confirmed.
return true;
} else {
// Wifi detected but no internet connection found.
return false;
}
} else {
// Neither mobile data or WIFI detected, not internet connection found.
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
该if (await DataConnectionChecker().hasConnection)部分对于移动和 wifi 连接是相同的,可能应该移至单独的功能。我没有在这里这样做以使其更具可读性。
这是我的第一个 Stack Overflow 答案,希望对某人有所帮助。
den*_*mat 26
对于在此居住的其他人,我想补充一下GünterZöchbauer的答案,这是我实施实用程序的解决方案,以了解是否有互联网,无论是否有其他东西。
免责声明:
我对Dart和Flutter都是新手,所以这可能不是最好的方法,但希望获得反馈。
我的要求
我不想在检查连接的任何地方都使用一堆重复的代码,而是希望它在发生更改时自动更新组件或其他任何关心连接的内容。
首先,我们设置一个Singleton。如果您不熟悉这种模式,则在线上有很多关于它们的好信息。但是要点是,您希望在应用程序生命周期中创建一个类的单个实例,并能够在任何地方使用它。
这个单例挂接到flutter_connectivity并监听连接性更改,然后测试网络连接,然后使用a StreamController更新所有需要的内容。
看起来像这样:
import 'dart:io'; //InternetAddress utility
import 'dart:async'; //For StreamController/Stream
import 'package:connectivity/connectivity.dart';
class ConnectionStatusSingleton {
//This creates the single instance by calling the `_internal` constructor specified below
static final ConnectionStatusSingleton _singleton = new ConnectionStatusSingleton._internal();
ConnectionStatusSingleton._internal();
//This is what's used to retrieve the instance through the app
static ConnectionStatusSingleton getInstance() => _singleton;
//This tracks the current connection status
bool hasConnection = false;
//This is how we'll allow subscribing to connection changes
StreamController connectionChangeController = new StreamController.broadcast();
//flutter_connectivity
final Connectivity _connectivity = Connectivity();
//Hook into flutter_connectivity's Stream to listen for changes
//And check the connection status out of the gate
void initialize() {
_connectivity.onConnectivityChanged.listen(_connectionChange);
checkConnection();
}
Stream get connectionChange => connectionChangeController.stream;
//A clean up method to close our StreamController
// Because this is meant to exist through the entire application life cycle this isn't
// really an issue
void dispose() {
connectionChangeController.close();
}
//flutter_connectivity's listener
void _connectionChange(ConnectivityResult result) {
checkConnection();
}
//The test to actually see if there is a connection
Future<bool> checkConnection() async {
bool previousConnection = hasConnection;
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
hasConnection = true;
} else {
hasConnection = false;
}
} on SocketException catch(_) {
hasConnection = false;
}
//The connection status changed send out an update to all listeners
if (previousConnection != hasConnection) {
connectionChangeController.add(hasConnection);
}
return hasConnection;
}
}
Run Code Online (Sandbox Code Playgroud)
初始化
首先,我们必须确保调用单例的初始化。但是只有一次。这取决于您,但是我在我的应用程序中做到了main():
void main() {
ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
connectionStatus.initialize();
runApp(MyApp());
//Call this if initialization is occuring in a scope that will end during app lifecycle
//connectionStatus.dispose();
}
Run Code Online (Sandbox Code Playgroud)
在Widget其他地方
import 'dart:async'; //For StreamSubscription
...
class MyWidgetState extends State<MyWidget> {
StreamSubscription _connectionChangeStream;
bool isOffline = false;
@override
initState() {
super.initState();
ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
_connectionChangeStream = connectionStatus.connectionChange.listen(connectionChanged);
}
void connectionChanged(dynamic hasConnection) {
setState(() {
isOffline = !hasConnection;
});
}
@override
Widget build(BuildContext ctxt) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
希望其他人觉得这有用!
示例github回购示例:https : //github.com/dennmat/flutter-connectiontest-example
在模拟器中切换飞行模式以查看结果
Tus*_*dey 10
使用
dependencies:
connectivity: ^0.4.2
Run Code Online (Sandbox Code Playgroud)
我们从资源中得到的是
import 'package:connectivity/connectivity.dart';
Future<bool> check() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
return true;
} else if (connectivityResult == ConnectivityResult.wifi) {
return true;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
对我来说,未来没什么大问题,我们必须像这样:
check().then((intenet) {
if (intenet != null && intenet) {
// Internet Present Case
}
// No-Internet Case
});
Run Code Online (Sandbox Code Playgroud)
因此,要解决此问题,我创建了一个类,该类接受带有boolean isNetworkPresent参数的函数,如下所示
methodName(bool isNetworkPresent){}
Run Code Online (Sandbox Code Playgroud)
实用程序类是
Run Code Online (Sandbox Code Playgroud)import 'package:connectivity/connectivity.dart'; class NetworkCheck { Future<bool> check() async { var connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult == ConnectivityResult.mobile) { return true; } else if (connectivityResult == ConnectivityResult.wifi) { return true; } return false; } dynamic checkInternet(Function func) { check().then((intenet) { if (intenet != null && intenet) { func(true); } else{ func(false); } }); } }
并使用连通性检查实用程序
fetchPrefrence(bool isNetworkPresent) {
if(isNetworkPresent){
}else{
}
}
Run Code Online (Sandbox Code Playgroud)
我将使用此语法
NetworkCheck networkCheck = new NetworkCheck();
networkCheck.checkInternet(fetchPrefrence)
Run Code Online (Sandbox Code Playgroud)
我创建了一个(我认为)可以可靠地处理这个问题的包。
非常欢迎讨论。您可以使用 GitHub 上的问题跟踪器。
我不再认为下面是一个可靠的方法:
想在@Oren 的回答中添加一些内容:您真的应该再添加一个 catch,它会捕获所有其他异常(为了安全起见),或者只是完全删除异常类型并使用处理所有异常的 catch:
情况1:
try {
await Firestore.instance
.runTransaction((Transaction tx) {})
.timeout(Duration(seconds: 5));
hasConnection = true;
} on PlatformException catch(_) { // May be thrown on Airplane mode
hasConnection = false;
} on TimeoutException catch(_) {
hasConnection = false;
} catch (_) {
hasConnection = false;
}
Run Code Online (Sandbox Code Playgroud)
甚至更简单...
案例2:
try {
await Firestore.instance
.runTransaction((Transaction tx) {})
.timeout(Duration(seconds: 5));
hasConnection = true;
} catch (_) {
hasConnection = false;
}
Run Code Online (Sandbox Code Playgroud)
嗯,我读了几乎所有的帖子,@dennmat 的帖子对我来说最有用。虽然它对我不起作用而且也已经过时了。我已经使用 flutter 更新connectivity包进行了更新(即connectivity_plus)和data_connection_checker(检查移动和 wifi 是否有实际的互联网连接)。
读完这篇文章后,您将能够持续监听互联网连接。
1. 添加依赖
a) connectivity_plus: ^1.0.6
b) data_connection_checker: ^0.3.4
2. 处理所有连接的自定义类。
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:data_connection_checker/data_connection_checker.dart';
class ConnectionUtil {
//This creates the single instance by calling the `_internal` constructor specified below
static final ConnectionUtil _singleton = new ConnectionUtil._internal();
ConnectionUtil._internal();
//This is what's used to retrieve the instance through the app
static ConnectionUtil getInstance() => _singleton;
//This tracks the current connection status
bool hasConnection = false;
//This is how we'll allow subscribing to connection changes
StreamController connectionChangeController = StreamController();
//flutter_connectivity
final Connectivity _connectivity = Connectivity();
void initialize() {
_connectivity.onConnectivityChanged.listen(_connectionChange);
}
//flutter_connectivity's listener
void _connectionChange(ConnectivityResult result) {
hasInternetInternetConnection();
}
Stream get connectionChange => connectionChangeController.stream;
Future<bool> hasInternetInternetConnection() async {
bool previousConnection = hasConnection;
var connectivityResult = await (Connectivity().checkConnectivity());
//Check if device is just connect with mobile network or wifi
if (connectivityResult == ConnectivityResult.mobile ||
connectivityResult == ConnectivityResult.wifi) {
//Check there is actual internet connection with a mobile network or wifi
if (await DataConnectionChecker().hasConnection) {
// Network data detected & internet connection confirmed.
hasConnection = true;
} else {
// Network data detected but no internet connection found.
hasConnection = false;
}
}
// device has no mobile network and wifi connection at all
else {
hasConnection = false;
}
// The connection status changed send out an update to all listeners
if (previousConnection != hasConnection) {
connectionChangeController.add(hasConnection);
}
return hasConnection;
}
}
Run Code Online (Sandbox Code Playgroud)
@override
initState() {
print('called');
//Create instance
ConnectionUtil connectionStatus = ConnectionUtil.getInstance();
//Initialize
connectionStatus.initialize();
//Listen for connection change
_connectionChangeStream = connectionStatus.connectionChange.listen((event) {
print(event);
});
super.initState();
}
Run Code Online (Sandbox Code Playgroud)
现在在切换飞行模式时检查日志。你应该得到带有 true 和 false 值的日志。
注意:这在 flutter web 中不起作用,如果你想让它工作而不是使用dio或httpplugin 而不是data_connection_checker.
示例项目可以在这里找到。谢谢
我为小部件状态创建了一个基类
使用而不是State<LoginPage>使用BaseState<LoginPage>
然后只使用布尔变量 isOnline
Text(isOnline ? 'is Online' : 'is Offline')
Run Code Online (Sandbox Code Playgroud)
首先,添加连接插件:
dependencies:
connectivity: ^0.4.3+2
Run Code Online (Sandbox Code Playgroud)
然后添加 BaseState 类
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:connectivity/connectivity.dart';
import 'package:flutter/widgets.dart';
/// a base class for any statful widget for checking internet connectivity
abstract class BaseState<T extends StatefulWidget> extends State {
void castStatefulWidget();
final Connectivity _connectivity = Connectivity();
StreamSubscription<ConnectivityResult> _connectivitySubscription;
/// the internet connectivity status
bool isOnline = true;
/// initialize connectivity checking
/// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initConnectivity() async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
await _connectivity.checkConnectivity();
} on PlatformException catch (e) {
print(e.toString());
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) {
return;
}
await _updateConnectionStatus().then((bool isConnected) => setState(() {
isOnline = isConnected;
}));
}
@override
void initState() {
super.initState();
initConnectivity();
_connectivitySubscription = Connectivity()
.onConnectivityChanged
.listen((ConnectivityResult result) async {
await _updateConnectionStatus().then((bool isConnected) => setState(() {
isOnline = isConnected;
}));
});
}
@override
void dispose() {
_connectivitySubscription.cancel();
super.dispose();
}
Future<bool> _updateConnectionStatus() async {
bool isConnected;
try {
final List<InternetAddress> result =
await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
isConnected = true;
}
} on SocketException catch (_) {
isConnected = false;
return false;
}
return isConnected;
}
}
Run Code Online (Sandbox Code Playgroud)
你需要像这样在你的状态下投射小部件
@override
void castStatefulWidget() {
// ignore: unnecessary_statements
widget is StudentBoardingPage;
}
Run Code Online (Sandbox Code Playgroud)
完整的示例演示了Internet连接及其源的侦听器。
归功于:连接性和GünterZöchbauer
import 'dart:async';
import 'dart:io';
import 'package:connectivity/connectivity.dart';
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Map _source = {ConnectivityResult.none: false};
MyConnectivity _connectivity = MyConnectivity.instance;
@override
void initState() {
super.initState();
_connectivity.initialise();
_connectivity.myStream.listen((source) {
setState(() => _source = source);
});
}
@override
Widget build(BuildContext context) {
String string;
switch (_source.keys.toList()[0]) {
case ConnectivityResult.none:
string = "Offline";
break;
case ConnectivityResult.mobile:
string = "Mobile: Online";
break;
case ConnectivityResult.wifi:
string = "WiFi: Online";
}
return Scaffold(
appBar: AppBar(title: Text("Internet")),
body: Center(child: Text("$string", style: TextStyle(fontSize: 36))),
);
}
@override
void dispose() {
_connectivity.disposeStream();
super.dispose();
}
}
class MyConnectivity {
MyConnectivity._internal();
static final MyConnectivity _instance = MyConnectivity._internal();
static MyConnectivity get instance => _instance;
Connectivity connectivity = Connectivity();
StreamController controller = StreamController.broadcast();
Stream get myStream => controller.stream;
void initialise() async {
ConnectivityResult result = await connectivity.checkConnectivity();
_checkStatus(result);
connectivity.onConnectivityChanged.listen((result) {
_checkStatus(result);
});
}
void _checkStatus(ConnectivityResult result) async {
bool isOnline = false;
try {
final result = await InternetAddress.lookup('example.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
isOnline = true;
} else
isOnline = false;
} on SocketException catch (_) {
isOnline = false;
}
controller.sink.add({result: isOnline});
}
void disposeStream() => controller.close();
}
Run Code Online (Sandbox Code Playgroud)
我对建议的解决方案有疑问,使用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;
}
Run Code Online (Sandbox Code Playgroud)
对 的调用_checkInternetAccess最多需要持续时间才能timeout完成(此处为 3 秒),如果我们可以到达任何 DNS,它将在到达第一个 DNS 后立即完成,而无需等待其他 DNS(因为到达一个就足以知道你有互联网)。所有的调用_pingDns都是并行完成的。
它似乎在 IPV4 网络上运行良好,当我无法在 IPV6 网络上测试它时(我无权访问),我认为它应该仍然可以工作。它也适用于发布模式构建,但我还必须将我的应用程序提交给 Apple,看看他们是否发现此解决方案有任何问题。
它也应该适用于大多数国家(包括中国),如果它在某个国家/地区不起作用,您可以将 DNS 添加到可从您的目标国家/地区访问的列表中。
| 归档时间: |
|
| 查看次数: |
31578 次 |
| 最近记录: |