我有一个网络调用要执行。但在此之前,我需要检查设备是否有互联网连接。
这是我目前为止所做的:
var connectivityResult = new Connectivity().checkConnectivity();// User defined class
if (connectivityResult == ConnectivityResult.mobile ||
connectivityResult == ConnectivityResult.wifi) {*/
this.getData();
} else {
neverSatisfied();
}
上述方法行不通。
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:app_settings/app_settings.dart';
import 'package:connectivity/connectivity.dart';
class InternetConnect extends StatefulWidget {
@override
InternetConnectState createState() => InternetConnectState();
}
class InternetConnectState extends State<InternetConnect> {
ConnectivityResult previous;
bool dialogshown = false;
StreamSubscription connectivitySubscription;
Future<bool> checkinternet() async {
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return Future.value(true);
}
} on SocketException catch (_) {
return Future.value(false);
}
}
void checkInternetConnect(BuildContext context) {
connectivitySubscription = Connectivity()
.onConnectivityChanged
.listen((ConnectivityResult connresult) {
if (connresult == ConnectivityResult.none) {
dialogshown = true;
showDialog(
context: context, barrierDismissible: false, child: alertDialog());
} else if (previous == ConnectivityResult.none) {
checkinternet().then((result) {
if (result == true) {
if (dialogshown == true) {
dialogshown = false;
Navigator.pop(context);
}
}
});
}
previous = connresult;
});
}
AlertDialog alertDialog() {
return AlertDialog(
title: Text('ERROR'),
content: Text("No Internet Detected."),
actions: <Widget>[
FlatButton(
// method to exit application programitacally
onPressed: () {
AppSettings.openWIFISettings();
},
child: Text("Settings"),
),
],
);
}
@override
Widget build(BuildContext context) {
return Container();
}
}
and you can use this method in init of any class
@override
void initState() {
// TODO: implement initState
InternetConnectState().checkInternetConnect(context);
super.initState();
}
我最终(虽然不情愿)选择了@abernee在之前回答这个问题时给出的解决方案。我总是尝试在我的项目中尽可能少地使用外部包——因为我知道外部包是我所创建的软件的唯一[潜在]故障点。所以链接到两个外部包只是为了一个简单的实现,像这样对我来说并不容易。
尽管如此,我还是采用了abernee的代码,并对其进行了修改,使其更精简、更合理。我说的明智是指他在自己的功能中消耗了Connectivity包的功能,但在内部由于没有从这个包中返回最有价值的输出(即网络标识)而浪费了它。这是阿伯尼解决方案的修改版本:
import 'package:connectivity/connectivity.dart';
import 'package:data_connection_checker/data_connection_checker.dart';
// 'McGyver' - the ultimate cool guy (the best helper class any app can ask for).
class McGyver {
static Future<Map<String, dynamic>> checkInternetAccess() async {
//* ////////////////////////////////////////////////////////////////////////////////////////// *//
//* INFO: ONLY TWO return TYPES for Map 'dynamic' value => <bool> and <ConnectivityResult> *//
//* ////////////////////////////////////////////////////////////////////////////////////////// *//
Map<String, dynamic> mapCon;
final String isConn = 'isConnected', netType = 'networkType';
ConnectivityResult conRes = await (Connectivity().checkConnectivity());
switch (conRes) {
case ConnectivityResult.wifi: //* WiFi Network: true !!
if (await DataConnectionChecker().hasConnection) { //* Internet Access: true !!
mapCon = Map.unmodifiable({isConn: true, netType: ConnectivityResult.wifi});
} else {
mapCon = Map.unmodifiable({isConn: false, netType: ConnectivityResult.wifi});
}
break;
case ConnectivityResult.mobile: //* Mobile Network: true !!
if (await DataConnectionChecker().hasConnection) { //* Internet Access: true !!
mapCon = Map.unmodifiable({isConn: true, netType: ConnectivityResult.mobile});
} else {
mapCon = Map.unmodifiable({isConn: false, netType: ConnectivityResult.mobile});
}
break;
case ConnectivityResult.none: //* No Network: true !!
mapCon = Map.unmodifiable({isConn: false, netType: ConnectivityResult.none});
break;
}
return mapCon;
}
}
然后你可以在代码中的任何地方通过简单的调用来使用这个静态函数,如下所示:
bool isConn; ConnectivityResult netType;
McGyver.checkInternetAccess().then(
(mapCIA) { //* 'mapCIA' == amalgamation for 'map' from 'CheckInternetAccess' function result.
debugPrint("'mapCIA' Keys: ${mapCIA.keys}");
isConn = mapCIA['isConnected'];
netType = mapCIA['networkType'];
}
);
debugPrint("Internet Access: $isConn | Network Type: $netType");
遗憾的是,你必须链接到两个外部包才能在你的Flutter项目中获得这个非常基本的功能-但我想目前这是我们拥有的最好的。实际上,我更喜欢数据连接检查器包而不是连接包——但是(在发布这篇文章的时候)前者缺少我从连接包中需要的非常重要的网络识别功能。这就是我(暂时)默认采用这种方法的原因。
我写了一个包来检查活跃的互联网连接和显示相应的小部件。
flutter_no_internet_widget
例子:
InternetWidget(
online: Text('Online'),
offline: Text('Offline),
);
根据网络状态,将显示适当的小部件。如果您有一个活跃的互联网连接,一个在线小部件将显示。
所有重量级的工作都由包完成,您所要做的就是提供在线和离线小部件。您还可以提供一个加载小部件和查找URL。
欢迎讨论、提交意见书或提出建议。
基于这个答案https://stackoverflow.com/a/68436867/10761151
如果你使用dart零安全,你会得到一个错误,
因此,您可以将依赖项data_connection_checker: ^0.3.4更新为internet_connection_checker: ^0.0.1+2
你可以用这个代码
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
class ConnectionUtil {
static final ConnectionUtil _singleton = new ConnectionUtil._internal();
ConnectionUtil._internal();
static ConnectionUtil getInstance() => _singleton;
bool hasConnection = false;
StreamController connectionChangeController = StreamController();
final Connectivity _connectivity = Connectivity();
void initialize() {
_connectivity.onConnectivityChanged.listen(_connectionChange);
}
void _connectionChange(ConnectivityResult result) {
_hasInternetInternetConnection();
}
Stream get connectionChange => connectionChangeController.stream;
Future<bool> _hasInternetInternetConnection() async {
bool previousConnection = hasConnection;
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile || connectivityResult == ConnectivityResult.wifi) {
// this is the different
if (await InternetConnectionChecker().hasConnection) {
hasConnection = true;
} else {
hasConnection = false;
}
} else {
hasConnection = false;
}
if (previousConnection != hasConnection) {
connectionChangeController.add(hasConnection);
}
return hasConnection;
}
}
在有状态小部件上可以实现此代码
bool hasInterNetConnection = false;
@override
initState() {
ConnectionUtil connectionStatus = ConnectionUtil.getInstance();
connectionStatus.initialize();
connectionStatus.connectionChange.listen(connectionChanged);
super.initState();
}
void connectionChanged(dynamic hasConnection) {
setState(() {
hasInterNetConnection = hasConnection;
});
}
这是我的解决方案,它检查互联网连接以及数据连接,我希望你喜欢它。
First of all add dependencies in your pubsec.yaml
dependencies:
data_connection_checker:
And Here Is The main.dart Of My Solution
import 'dart:async';
import 'package:data_connection_checker/data_connection_checker.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Data Connection Checker",
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
StreamSubscription<DataConnectionStatus> listener;
var Internetstatus = "Unknown";
@override
void initState() {
// TODO: implement initState
super.initState();
// _updateConnectionStatus();
CheckInternet();
}
@override
void dispose() {
// TODO: implement dispose
listener.cancel();
super.dispose();
}
CheckInternet() async {
// Simple check to see if we have internet
print("The statement 'this machine is connected to the Internet' is: ");
print(await DataConnectionChecker().hasConnection);
// returns a bool
// We can also get an enum instead of a bool
print("Current status: ${await DataConnectionChecker().connectionStatus}");
// prints either DataConnectionStatus.connected
// or DataConnectionStatus.disconnected
// This returns the last results from the last call
// to either hasConnection or connectionStatus
print("Last results: ${DataConnectionChecker().lastTryResults}");
// actively listen for status updates
listener = DataConnectionChecker().onStatusChange.listen((status) {
switch (status) {
case DataConnectionStatus.connected:
Internetstatus="Connectd TO THe Internet";
print('Data connection is available.');
setState(() {
});
break;
case DataConnectionStatus.disconnected:
Internetstatus="No Data Connection";
print('You are disconnected from the internet.');
setState(() {
});
break;
}
});
// close listener after 30 seconds, so the program doesn't run forever
// await Future.delayed(Duration(seconds: 30));
// await listener.cancel();
return await await DataConnectionChecker().connectionStatus;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Data Connection Checker"),
),
body: Container(
child: Center(
child: Text("$Internetstatus"),
),
),
);
}
}
在@dennmatt的回答之后,我注意到InternetAddress。查找可能会返回成功的结果,即使互联网连接断开-我测试它从我的模拟器连接到我的家庭WiFi,然后断开我的路由器的电缆。我认为原因是路由器缓存了域查找结果,所以它不必在每个查找请求时查询DNS服务器。
不管怎样,如果你像我一样使用Firestore,你可以用一个空事务替换try-SocketException-catch块并捕获TimeoutExceptions:
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;
}
另外,请注意,previousConnection是在async internet -check之前设置的,因此理论上,如果checkConnection()在短时间内被调用多次,那么在一行中可能有多个hasConnection=true或多个hasConnection=false。
我不确定@dennmatt是否故意这样做,但在我们的用例中没有副作用(setState只被调用两次,具有相同的值)。