检查 Flutter 应用程序是否有可用的互联网连接
Check whether there is an Internet connection available on Flutter app
我有一个网络调用要执行。但在此之前,我需要检查设备是否具有互联网连接。
这是我目前所做的:
var connectivityResult = new Connectivity().checkConnectivity();// User defined class
if (connectivityResult == ConnectivityResult.mobile ||
connectivityResult == ConnectivityResult.wifi) {*/
this.getData();
} else {
neverSatisfied();
}
以上方法无效。
connectivity 插件在其文档中声明它仅在有网络连接时提供信息,但在网络连接到 Internet 时不提供信息
Note that on Android, this does not guarantee connection to Internet. For instance, the app might have wifi access but it might be a VPN or a hotel WiFi with no access.
您可以使用
import 'dart:io';
...
try {
final result = await InternetAddress.lookup('example.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
print('connected');
}
} on SocketException catch (_) {
print('not connected');
}
对于来到这里的任何其他人,我想补充一下 Günter Zöchbauer 的回答,这是我实现一个实用程序的解决方案,无论其他情况如何,都知道是否有互联网。
免责声明:
我是 Dart 和 Flutter 的新手,所以这可能不是最好的方法,但希望得到反馈。
结合 flutter_connectivity 和 Günter Zöchbauer 的连接测试
我的要求
我不想在任何需要检查连接的地方都有一堆重复的代码,我希望它在发生变化时自动更新组件或任何其他关心连接的东西。
ConnectionStatusSingleton
首先我们设置一个单例。如果您不熟悉这种模式,网上有很多关于它们的有用信息。但要点是您希望在应用程序生命周期中创建 class 的单个实例,并能够在任何地方使用它。
此单例连接到 flutter_connectivity
并监听连接变化,然后测试网络连接,然后使用 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;
}
}
用法
初始化
首先我们必须确保我们调用了单例的初始化。但只有一次。
这取决于你,但我是在我的应用程序 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();
}
在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) {
...
}
}
希望其他人觉得这有用!
示例 github 回购:https://github.com/dennmat/flutter-connectiontest-example
在模拟器中切换飞行模式以查看结果
使用
dependencies:
connectivity: ^0.4.2
我们从 resouces 得到的是
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;
}
Future 对我来说没什么问题,我们必须每次都实现它,例如:
check().then((intenet) {
if (intenet != null && intenet) {
// Internet Present Case
}
// No-Internet Case
});
所以为了解决这个问题,我创建了一个 class 它接受一个带有布尔 isNetworkPresent 参数的函数,就像这样
methodName(bool isNetworkPresent){}
效用 Class 是
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{
}
}
我将使用这种语法
NetworkCheck networkCheck = new NetworkCheck();
networkCheck.checkInternet(fetchPrefrence)
在 @dennmatt 的 之后,我注意到 InternetAddress.lookup
可能会 return 成功结果,即使互联网连接已关闭 - 我通过从我的模拟器连接到我的模拟器来测试它家庭 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
设置在异步intenet-check之前,所以理论上如果checkConnection()
在短时间内被多次调用,可能会有多个hasConnection=true
连续或连续多个 hasConnection=false
。
我不确定@dennmatt 是否有意这样做,但在我们的用例中没有副作用(setState
仅使用相同的值调用了两次)。
我创建了一个包(我认为)可以可靠地处理这个问题。
非常欢迎讨论。您可以在 GitHub.
上使用问题跟踪器
我不再认为下面这个是可靠的方法:
想在 @Oren's 答案中添加一些东西:你真的应该再添加一个 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;
}
甚至更简单...
案例二:
try {
await Firestore.instance
.runTransaction((Transaction tx) {})
.timeout(Duration(seconds: 5));
hasConnection = true;
} catch (_) {
hasConnection = false;
}
我为小部件状态做了一个基础class
用法而不是 State<LoginPage>
使用 BaseState<LoginPage>
然后只需使用布尔变量 isOnline
Text(isOnline ? 'is Online' : 'is Offline')
首先,添加连接插件:
dependencies:
connectivity: ^0.4.3+2
然后添加BaseStateclass
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;
}
}
并且您需要像这样在您的状态下投射小部件
@override
void castStatefulWidget() {
// ignore: unnecessary_statements
widget is StudentBoardingPage;
}
空安全代码:
一次性检查:
创建此方法:
Future<bool> hasNetwork() async {
try {
final result = await InternetAddress.lookup('example.com');
return result.isNotEmpty && result[0].rawAddress.isNotEmpty;
} on SocketException catch (_) {
return false;
}
}
用法:
bool isOnline = await hasNetwork();
正在设置侦听器:
将以下依赖项添加到您的 pubspec.yaml
文件中。
connectivity_plus: ^2.0.2
完整代码:
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Map _source = {ConnectivityResult.none: false};
final 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.mobile:
string = 'Mobile: Online';
break;
case ConnectivityResult.wifi:
string = 'WiFi: Online';
break;
case ConnectivityResult.none:
default:
string = 'Offline';
}
return Scaffold(
body: Center(child: Text(string)),
);
}
@override
void dispose() {
_connectivity.disposeStream();
super.dispose();
}
}
class MyConnectivity {
MyConnectivity._();
static final _instance = MyConnectivity._();
static MyConnectivity get instance => _instance;
final _connectivity = Connectivity();
final _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');
isOnline = result.isNotEmpty && result[0].rawAddress.isNotEmpty;
} on SocketException catch (_) {
isOnline = false;
}
_controller.sink.add({result: isOnline});
}
void disposeStream() => _controller.close();
}
截图:
感谢:connectivity_plus 和 Günter Zöchbauer
连接性:包不保证实际的互联网连接
(可能只是没有互联网访问的 wifi 连接)。
引自文档:
Note that on Android, this does not guarantee connection to Internet. For instance, the app might have wifi access but it might be a VPN or a hotel WiFi with no access.
如果您确实需要检查与 www Internet 的连接,更好的选择是
只是想在 Flutter 中使用 Connectivity Package 来简化代码。
import 'package:connectivity/connectivity.dart';
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
// I am connected to a mobile network.
} else if (connectivityResult == ConnectivityResult.wifi) {
// I am connected to a wifi network.
} else {
// I am not connected to the internet
}
迟到的答案,但使用这个包来检查。
包名:data_connection_checker
在你的pubspec.yuml文件中:
dependencies:
data_connection_checker: ^0.3.4
创建一个名为 connection.dart 或您想要的任何名称的文件。
导入包:
import 'package:data_connection_checker/data_connection_checker.dart';
检查是否有互联网连接:
print(await DataConnectionChecker().hasConnection);
我发现仅使用 connectivity 包不足以判断互联网是否可用。在 Android 中它只检查是否有 WIFI 或移动数据是否打开,它不检查实际的互联网连接。在我的测试中,即使没有移动信号 ConnectivityResult.mobile 也会 return 为真。
对于 IOS,我的测试发现当 phone 没有信号时,连接插件确实可以正确检测是否存在互联网连接,问题仅在于 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;
}
}
if (await DataConnectionChecker().hasConnection)
部分对于移动和 wifi 连接是相同的,可能应该移到一个单独的函数中。我在这里没有这样做是为了让它更具可读性。
这是我在 Stack Overflow 上的第一个回答,希望对大家有所帮助。
这是我的解决方案,它检查 Internet 连接和数据连接,希望您喜欢。
首先在你的 pubsec.yaml 中添加依赖项
dependencies:
data_connection_checker:
这是我的解决方案 main.dart
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"),
),
),
);
}
}
我最终(虽然不情愿)决定了@abernee 在 中对这个问题给出的解决方案。我总是尝试在我的项目中使用尽可能少的外部包——因为我知道外部包是我创建的软件中唯一的[潜在]故障点。所以 link 到 两个 外部包只是为了像这样的简单实现 对我来说并不容易。
尽管如此,我还是采用了 abernee 的代码并对其进行了修改,使其更精简、更明智。明智的我的意思是他在他的函数中消耗了 Connectivity package 的力量,但随后通过不从该包返回最有价值的输出(即网络标识)而在内部浪费了它。所以这里是 abernee 解决方案的修改版本:
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");
遗憾的是,您必须 link 到 两个外部包 才能在您的 Flutter 中获得这个非常 基本功能 项目 - 但我想现在这是我们拥有的最好的项目。我实际上更喜欢 Data Connection Checker package over the Connectivity 包 - 但是(在发布此信息时)前者缺少我从 Connectivity 包中需要的非常重要的 网络识别功能 。这就是我 [暂时] 默认采用这种方法的原因。
我对建议的解决方案有疑问,使用 lookup
并不总是 return 预期值。
这是由于 DNS 缓存,调用的值被缓存,而不是在下一次尝试进行正确的调用时返回缓存的值。当然这是一个问题,因为这意味着如果你失去连接并调用 lookup
它仍然可以 return 缓存值,就像你有互联网一样,相反,如果你在 [=11] 之后重新连接互联网=] returned null 它在缓存期间仍然 return null,这可能是几分钟,即使您现在有互联网。
TL;DR: lookup
return 上网并不一定意味着你有互联网,没有 return 任何东西并不一定意味着你没有互联网。不靠谱。
我从 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;
}
对 _checkInternetAccess
的调用最多需要 timeout
的持续时间才能完成(此处为 3 秒),如果我们可以访问任何 DNS,它将在第一个 DNS 时完成到达,无需等待其他人(因为到达一个就足以知道您有互联网)。所有对 _pingDns
的调用都是并行完成的。
它似乎在 IPV4 网络上运行良好,当我无法在 IPV6 网络上测试它时(我无法访问它)我认为它应该仍然可以运行。它也适用于发布模式构建,但我还必须将我的应用程序提交给 Apple,看看他们是否发现此解决方案有任何问题。
它应该也适用于大多数国家(包括中国),如果它在某个国家/地区不起作用,您可以将 DNS 添加到可从目标国家/地区访问的列表中。
我使用 data_connection_checker 包来检查互联网访问,即使通过 wifi 或手机连接可用,它也能正常工作:
这是检查连接的代码:
bool result = await DataConnectionChecker().hasConnection;
if(result == true) {
print('YAY! Free cute dog pics!');
} else {
print('No internet :( Reason:');
print(DataConnectionChecker().lastTryResults);
}
如果您想了解更多信息,请查看包裹。
Data Connection Checker Package
我对已接受的答案有一些疑问,但它似乎解决了其他人的答案。我想要一个可以从它使用的 url 获得响应的解决方案,所以我认为 http 非常适合该功能,为此我发现这个答案真的很有帮助。
对我来说,我只是在 Firebase 中创建一个数据,然后使用 future builder 等待数据。在这里,像这样,您可以检查连接是否太慢,以便加载数据:
FutureBuilder(
future: _getImage(context),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return Container(
height:
MediaQuery.of(context).size.height / 1.25,
width:
MediaQuery.of(context).size.width / 1.25,
child: Loading());
case ConnectionState.done:
if (snapshot.hasData) {
return snapshot.data;
} else {
return FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ProfilePage()));
},
child: Icon(
Icons.add_a_photo,
size: 50,
),
);
}
// You can reach your snapshot.data['url'] in here
}
return null;
},
),
添加依赖:
dependencies:
connectivity_widget: ^0.1.7
添加代码:
ConnectivityWidget(
builder: (context, isOnline) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"${isOnline ? 'Connected' : 'Offline'}",
style: TextStyle(
fontSize: 30,
color: isOnline ? Colors.green : Colors.red),
),
],
),
),
)
输出:
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();
}
嗯,我读了几乎所有 post,@dennmat post 对我最有用。虽然它对我不起作用而且它也已经过时了。我更新了 flutter updated connectivity
包(即 connectivity_plus
)和 data_connection_checker
(检查是否有移动和 wifi 的实际互联网连接)。
在此之后post您将能够连续侦听互联网连接。
1.添加依赖项
一)connectivity_plus: ^1.0.6
b) data_connection_checker: ^0.3.4
2。处理所有连接的自定义 class。
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;
}
}
- 在任何地方检查连接并监听变化。
@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();
}
现在在切换飞行模式时检查日志。你应该得到带有 true 和 false 值的日志。
注意:这在 flutter web 中不起作用,如果你想让它起作用而不是使用 dio
或 http
插件而不是 data_connection_checker
.
可以找到示例项目 here。谢谢
基于这个答案
如果你使用了 dart null safety 你会得到一个错误,
所以你可以更新依赖项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;
});
}
你可以使用这个包
https://pub.dev/packages/flutter_network_connectivity
在底层,它使用 Android 上的 NetworkCapabilities 和 iOS 上的 NetworkMonitor 并监听连接变化和 ping 以检查互联网可用性,您还可以配置为定期查找互联网可用性。
添加到您的pubspec.yaml
flutter_network_connectivity: ^0.0.6
创建对象
FlutterNetworkConnectivity flutterNetworkConnectivity =
FlutterNetworkConnectivity(
isContinousLookUp: true, // optional, false if you cont want continous lookup
lookUpDuration: const Duration(seconds: 5), // optional, to override default lookup duration
lookUpUrl: 'example.com', // optional, to override default lookup url
);
并且您可以使用其方法连续检查网络连接或调用检查当前状态
_flutterNetworkConnectivity.getInternetAvailabilityStream().listen((isInternetAvailable) {
// do something
});
并注册监听器
await _flutterNetworkConnectivity.registerAvailabilityListener();
检查通话状态
bool _isNetworkConnectedOnCall = await _flutterNetworkConnectivity.isInternetConnectionAvailable();
连接插件在其文档中指出,它仅在存在网络连接时提供信息,但在网络连接到 Internet 时不提供信息。使用下面的代码,不要忘记使用“.timeout()”,因为使用“await”可能会永远卡住。
import 'dart:io';
Future<bool> isConnected() async {
try {
List<InternetAddress> result = await InternetAddress.lookup('example.com')
.timeout(Duration(seconds: 5));
//
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
}
//
else {
return false;
}
} on SocketException catch (_) {
return false;
}
}
我已经编写了一个程序包来检查活动的互联网连接并相应地显示一个小部件。
示例:
InternetWidget(
online: Text('Online'),
offline: Text('Offline),
);
根据网络状态,将显示相应的小部件。如果您有有效的互联网连接,将显示一个在线小部件。
所有重量级的包都搞定了,你只需要提供线上线下的widgets。您可以选择提供加载小部件和查找 URL.
欢迎讨论、PR 或建议。
最终 ConnectivityResult 结果 =
await Connectivity().checkConnectivity();
if (result == ConnectivityResult.wifi) {
print('Connected to a Wi-Fi network');
} else if (result == ConnectivityResult.mobile) {
print('Connected to a mobile network');
} else {
print('Not connected to any network');
}
我有一个网络调用要执行。但在此之前,我需要检查设备是否具有互联网连接。
这是我目前所做的:
var connectivityResult = new Connectivity().checkConnectivity();// User defined class
if (connectivityResult == ConnectivityResult.mobile ||
connectivityResult == ConnectivityResult.wifi) {*/
this.getData();
} else {
neverSatisfied();
}
以上方法无效。
connectivity 插件在其文档中声明它仅在有网络连接时提供信息,但在网络连接到 Internet 时不提供信息
Note that on Android, this does not guarantee connection to Internet. For instance, the app might have wifi access but it might be a VPN or a hotel WiFi with no access.
您可以使用
import 'dart:io';
...
try {
final result = await InternetAddress.lookup('example.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
print('connected');
}
} on SocketException catch (_) {
print('not connected');
}
对于来到这里的任何其他人,我想补充一下 Günter Zöchbauer 的回答,这是我实现一个实用程序的解决方案,无论其他情况如何,都知道是否有互联网。
免责声明:
我是 Dart 和 Flutter 的新手,所以这可能不是最好的方法,但希望得到反馈。
结合 flutter_connectivity 和 Günter Zöchbauer 的连接测试
我的要求
我不想在任何需要检查连接的地方都有一堆重复的代码,我希望它在发生变化时自动更新组件或任何其他关心连接的东西。
ConnectionStatusSingleton
首先我们设置一个单例。如果您不熟悉这种模式,网上有很多关于它们的有用信息。但要点是您希望在应用程序生命周期中创建 class 的单个实例,并能够在任何地方使用它。
此单例连接到 flutter_connectivity
并监听连接变化,然后测试网络连接,然后使用 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;
}
}
用法
初始化
首先我们必须确保我们调用了单例的初始化。但只有一次。
这取决于你,但我是在我的应用程序 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();
}
在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) {
...
}
}
希望其他人觉得这有用!
示例 github 回购:https://github.com/dennmat/flutter-connectiontest-example
在模拟器中切换飞行模式以查看结果
使用
dependencies:
connectivity: ^0.4.2
我们从 resouces 得到的是
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;
}
Future 对我来说没什么问题,我们必须每次都实现它,例如:
check().then((intenet) {
if (intenet != null && intenet) {
// Internet Present Case
}
// No-Internet Case
});
所以为了解决这个问题,我创建了一个 class 它接受一个带有布尔 isNetworkPresent 参数的函数,就像这样
methodName(bool isNetworkPresent){}
效用 Class 是
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{
}
}
我将使用这种语法
NetworkCheck networkCheck = new NetworkCheck();
networkCheck.checkInternet(fetchPrefrence)
在 @dennmatt 的 InternetAddress.lookup
可能会 return 成功结果,即使互联网连接已关闭 - 我通过从我的模拟器连接到我的模拟器来测试它家庭 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
设置在异步intenet-check之前,所以理论上如果checkConnection()
在短时间内被多次调用,可能会有多个hasConnection=true
连续或连续多个 hasConnection=false
。
我不确定@dennmatt 是否有意这样做,但在我们的用例中没有副作用(setState
仅使用相同的值调用了两次)。
我创建了一个包(我认为)可以可靠地处理这个问题。
非常欢迎讨论。您可以在 GitHub.
上使用问题跟踪器我不再认为下面这个是可靠的方法:
想在 @Oren's 答案中添加一些东西:你真的应该再添加一个 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;
}
甚至更简单...
案例二:
try {
await Firestore.instance
.runTransaction((Transaction tx) {})
.timeout(Duration(seconds: 5));
hasConnection = true;
} catch (_) {
hasConnection = false;
}
我为小部件状态做了一个基础class
用法而不是 State<LoginPage>
使用 BaseState<LoginPage>
然后只需使用布尔变量 isOnline
Text(isOnline ? 'is Online' : 'is Offline')
首先,添加连接插件:
dependencies:
connectivity: ^0.4.3+2
然后添加BaseStateclass
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;
}
}
并且您需要像这样在您的状态下投射小部件
@override
void castStatefulWidget() {
// ignore: unnecessary_statements
widget is StudentBoardingPage;
}
空安全代码:
一次性检查:
创建此方法:
Future<bool> hasNetwork() async { try { final result = await InternetAddress.lookup('example.com'); return result.isNotEmpty && result[0].rawAddress.isNotEmpty; } on SocketException catch (_) { return false; } }
用法:
bool isOnline = await hasNetwork();
正在设置侦听器:
将以下依赖项添加到您的
pubspec.yaml
文件中。connectivity_plus: ^2.0.2
完整代码:
void main() => runApp(MaterialApp(home: HomePage())); class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { Map _source = {ConnectivityResult.none: false}; final 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.mobile: string = 'Mobile: Online'; break; case ConnectivityResult.wifi: string = 'WiFi: Online'; break; case ConnectivityResult.none: default: string = 'Offline'; } return Scaffold( body: Center(child: Text(string)), ); } @override void dispose() { _connectivity.disposeStream(); super.dispose(); } } class MyConnectivity { MyConnectivity._(); static final _instance = MyConnectivity._(); static MyConnectivity get instance => _instance; final _connectivity = Connectivity(); final _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'); isOnline = result.isNotEmpty && result[0].rawAddress.isNotEmpty; } on SocketException catch (_) { isOnline = false; } _controller.sink.add({result: isOnline}); } void disposeStream() => _controller.close(); }
截图:
感谢:connectivity_plus 和 Günter Zöchbauer
连接性:包不保证实际的互联网连接 (可能只是没有互联网访问的 wifi 连接)。
引自文档:
Note that on Android, this does not guarantee connection to Internet. For instance, the app might have wifi access but it might be a VPN or a hotel WiFi with no access.
如果您确实需要检查与 www Internet 的连接,更好的选择是
只是想在 Flutter 中使用 Connectivity Package 来简化代码。
import 'package:connectivity/connectivity.dart';
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
// I am connected to a mobile network.
} else if (connectivityResult == ConnectivityResult.wifi) {
// I am connected to a wifi network.
} else {
// I am not connected to the internet
}
迟到的答案,但使用这个包来检查。 包名:data_connection_checker
在你的pubspec.yuml文件中:
dependencies:
data_connection_checker: ^0.3.4
创建一个名为 connection.dart 或您想要的任何名称的文件。 导入包:
import 'package:data_connection_checker/data_connection_checker.dart';
检查是否有互联网连接:
print(await DataConnectionChecker().hasConnection);
我发现仅使用 connectivity 包不足以判断互联网是否可用。在 Android 中它只检查是否有 WIFI 或移动数据是否打开,它不检查实际的互联网连接。在我的测试中,即使没有移动信号 ConnectivityResult.mobile 也会 return 为真。
对于 IOS,我的测试发现当 phone 没有信号时,连接插件确实可以正确检测是否存在互联网连接,问题仅在于 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;
}
}
if (await DataConnectionChecker().hasConnection)
部分对于移动和 wifi 连接是相同的,可能应该移到一个单独的函数中。我在这里没有这样做是为了让它更具可读性。
这是我在 Stack Overflow 上的第一个回答,希望对大家有所帮助。
这是我的解决方案,它检查 Internet 连接和数据连接,希望您喜欢。
首先在你的 pubsec.yaml 中添加依赖项dependencies:
data_connection_checker:
这是我的解决方案 main.dart
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"),
),
),
);
}
}
我最终(虽然不情愿)决定了@abernee 在
尽管如此,我还是采用了 abernee 的代码并对其进行了修改,使其更精简、更明智。明智的我的意思是他在他的函数中消耗了 Connectivity package 的力量,但随后通过不从该包返回最有价值的输出(即网络标识)而在内部浪费了它。所以这里是 abernee 解决方案的修改版本:
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");
遗憾的是,您必须 link 到 两个外部包 才能在您的 Flutter 中获得这个非常 基本功能 项目 - 但我想现在这是我们拥有的最好的项目。我实际上更喜欢 Data Connection Checker package over the Connectivity 包 - 但是(在发布此信息时)前者缺少我从 Connectivity 包中需要的非常重要的 网络识别功能 。这就是我 [暂时] 默认采用这种方法的原因。
我对建议的解决方案有疑问,使用 lookup
并不总是 return 预期值。
这是由于 DNS 缓存,调用的值被缓存,而不是在下一次尝试进行正确的调用时返回缓存的值。当然这是一个问题,因为这意味着如果你失去连接并调用 lookup
它仍然可以 return 缓存值,就像你有互联网一样,相反,如果你在 [=11] 之后重新连接互联网=] returned null 它在缓存期间仍然 return null,这可能是几分钟,即使您现在有互联网。
TL;DR: lookup
return 上网并不一定意味着你有互联网,没有 return 任何东西并不一定意味着你没有互联网。不靠谱。
我从 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;
}
对 _checkInternetAccess
的调用最多需要 timeout
的持续时间才能完成(此处为 3 秒),如果我们可以访问任何 DNS,它将在第一个 DNS 时完成到达,无需等待其他人(因为到达一个就足以知道您有互联网)。所有对 _pingDns
的调用都是并行完成的。
它似乎在 IPV4 网络上运行良好,当我无法在 IPV6 网络上测试它时(我无法访问它)我认为它应该仍然可以运行。它也适用于发布模式构建,但我还必须将我的应用程序提交给 Apple,看看他们是否发现此解决方案有任何问题。
它应该也适用于大多数国家(包括中国),如果它在某个国家/地区不起作用,您可以将 DNS 添加到可从目标国家/地区访问的列表中。
我使用 data_connection_checker 包来检查互联网访问,即使通过 wifi 或手机连接可用,它也能正常工作: 这是检查连接的代码:
bool result = await DataConnectionChecker().hasConnection;
if(result == true) {
print('YAY! Free cute dog pics!');
} else {
print('No internet :( Reason:');
print(DataConnectionChecker().lastTryResults);
}
如果您想了解更多信息,请查看包裹。 Data Connection Checker Package
我对已接受的答案有一些疑问,但它似乎解决了其他人的答案。我想要一个可以从它使用的 url 获得响应的解决方案,所以我认为 http 非常适合该功能,为此我发现这个答案真的很有帮助。
对我来说,我只是在 Firebase 中创建一个数据,然后使用 future builder 等待数据。在这里,像这样,您可以检查连接是否太慢,以便加载数据:
FutureBuilder(
future: _getImage(context),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return Container(
height:
MediaQuery.of(context).size.height / 1.25,
width:
MediaQuery.of(context).size.width / 1.25,
child: Loading());
case ConnectionState.done:
if (snapshot.hasData) {
return snapshot.data;
} else {
return FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ProfilePage()));
},
child: Icon(
Icons.add_a_photo,
size: 50,
),
);
}
// You can reach your snapshot.data['url'] in here
}
return null;
},
),
添加依赖:
dependencies:
connectivity_widget: ^0.1.7
添加代码:
ConnectivityWidget(
builder: (context, isOnline) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"${isOnline ? 'Connected' : 'Offline'}",
style: TextStyle(
fontSize: 30,
color: isOnline ? Colors.green : Colors.red),
),
],
),
),
)
输出:
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();
}
嗯,我读了几乎所有 post,@dennmat post 对我最有用。虽然它对我不起作用而且它也已经过时了。我更新了 flutter updated connectivity
包(即 connectivity_plus
)和 data_connection_checker
(检查是否有移动和 wifi 的实际互联网连接)。
在此之后post您将能够连续侦听互联网连接。
1.添加依赖项
一)connectivity_plus: ^1.0.6
b) data_connection_checker: ^0.3.4
2。处理所有连接的自定义 class。
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;
}
}
- 在任何地方检查连接并监听变化。
@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();
}
现在在切换飞行模式时检查日志。你应该得到带有 true 和 false 值的日志。
注意:这在 flutter web 中不起作用,如果你想让它起作用而不是使用 dio
或 http
插件而不是 data_connection_checker
.
可以找到示例项目 here。谢谢
基于这个答案
如果你使用了 dart null safety 你会得到一个错误, 所以你可以更新依赖项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;
});
}
你可以使用这个包 https://pub.dev/packages/flutter_network_connectivity
在底层,它使用 Android 上的 NetworkCapabilities 和 iOS 上的 NetworkMonitor 并监听连接变化和 ping 以检查互联网可用性,您还可以配置为定期查找互联网可用性。
添加到您的pubspec.yaml
flutter_network_connectivity: ^0.0.6
创建对象
FlutterNetworkConnectivity flutterNetworkConnectivity =
FlutterNetworkConnectivity(
isContinousLookUp: true, // optional, false if you cont want continous lookup
lookUpDuration: const Duration(seconds: 5), // optional, to override default lookup duration
lookUpUrl: 'example.com', // optional, to override default lookup url
);
并且您可以使用其方法连续检查网络连接或调用检查当前状态
_flutterNetworkConnectivity.getInternetAvailabilityStream().listen((isInternetAvailable) {
// do something
});
并注册监听器
await _flutterNetworkConnectivity.registerAvailabilityListener();
检查通话状态
bool _isNetworkConnectedOnCall = await _flutterNetworkConnectivity.isInternetConnectionAvailable();
连接插件在其文档中指出,它仅在存在网络连接时提供信息,但在网络连接到 Internet 时不提供信息。使用下面的代码,不要忘记使用“.timeout()”,因为使用“await”可能会永远卡住。
import 'dart:io';
Future<bool> isConnected() async {
try {
List<InternetAddress> result = await InternetAddress.lookup('example.com')
.timeout(Duration(seconds: 5));
//
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
}
//
else {
return false;
}
} on SocketException catch (_) {
return false;
}
}
我已经编写了一个程序包来检查活动的互联网连接并相应地显示一个小部件。
示例:
InternetWidget(
online: Text('Online'),
offline: Text('Offline),
);
根据网络状态,将显示相应的小部件。如果您有有效的互联网连接,将显示一个在线小部件。
所有重量级的包都搞定了,你只需要提供线上线下的widgets。您可以选择提供加载小部件和查找 URL.
欢迎讨论、PR 或建议。
最终 ConnectivityResult 结果 = await Connectivity().checkConnectivity();
if (result == ConnectivityResult.wifi) {
print('Connected to a Wi-Fi network');
} else if (result == ConnectivityResult.mobile) {
print('Connected to a mobile network');
} else {
print('Not connected to any network');
}