Flutterアプリで利用可能なインターネット接続があるかどうかを確認します


99

実行するネットワーク呼び出しがあります。ただし、その前に、デバイスにインターネット接続があるかどうかを確認する必要があります。

これは私がこれまでに行ったことです:

  var connectivityResult = new Connectivity().checkConnectivity();// User defined class
    if (connectivityResult == ConnectivityResult.mobile ||
        connectivityResult == ConnectivityResult.wifi) {*/
    this.getData();
    } else {
      neverSatisfied();
    }

上記の方法は機能しません。

回答:


192

接続ネットワークがインターネットに接続されている場合、それが唯一のネットワーク接続がある場合の情報を提供していますが、ではないことを、そのドキュメント内の状態のプラグイン

Androidでは、これはインターネットへの接続を保証するものではないことに注意してください。たとえば、アプリはWi-Fiにアクセスできますが、VPNまたはホテルのWi-Fiにアクセスできない場合があります。

あなたが使用することができます

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');
}

2
「isNotEmptyはInternetAddress内で宣言されていません」というエラーが発生します
Rissmon Suresh 2018

2
これはバックグラウンドで達成できますか?実行待ちでインターネットを待っているタスクのキューがありますが、アプリは閉じていますか?
Vidor Vistrom 2018年

60
google.comは中国国内ではアクセスできないため、中国で使用すると例がハングすることに注意してください。オーディエンスを拡大するには、google.comの使用を避け、代わりにexample.comを使用してください。最終結果= await InternetAddress.lookup( 'example.com');
otboss

4
これは私にとってif (result.isNotEmpty && result[0].rawAddress.isNotEmpty)は機能しません。wifiはあるがインターネット接続がない場合はtrueを返します。
デン

5
ああ、はい、私はこれを完全に忘れました!実は使い続けられると思いawaitますが.timeout、あとに追加するだけlookup()です。
ミシェル・ファインスタイン

73

ここに着陸した他の人にとっては、GünterZöchbauerの答えに追加したいと思います。これは、インターネットがあるかどうかを知るためのユーティリティを実装するための私のソリューションでした。

免責事項:

私はDartとFlutterの両方に慣れていないので、これは最善のアプローチではないかもしれませんが、フィードバックを受け取りたいと思っています。


flutter_connectivityとGünterZöchbauerの接続テストを組み合わせる

私の要件

接続を確認する必要がある場所に大量のコードを繰り返したくはありませんでした。また、変更があったときはいつでも、コンポーネントや接続を気にするその他のものを自動的に更新する必要がありました。

ConnectionStatusSingleton

まず、シングルトンをセットアップします。このパターンに慣れていない場合は、オンラインで多くの有益な情報があります。ただし、要点は、アプリケーションのライフサイクル中にクラスの単一インスタンスを作成し、それをどこでも使用できるようにすることです。

このシングルトン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

エミュレータで機内モードを切り替えて、結果を確認します


2
コードをテストしましたが、それは私のために機能しています。私は助けるためにもっと情報が必要です。
dennmat 2018

3
ああ、わかりました。したがって、今後の参考のために、投稿しているエラーは、エラーが発生したと思われるファイルを編集者が開こうとしているだけです。実際のエラーは、エディターのデバッグコンソール/スタックトレースパネルで確認できます。したがって、runAppは、プログラムの存続期間全体にわたって実行されると想定して戻ってきたと思います。これがメインであるため、ここでは破棄は実際には必要ないのでconnectionStatus.dispose()main()上記のように設定していると想定して削除します。投稿を更新し、githubの例にリンクします。
dennmat 2018

1
Wi-Fiまたはセルラーが切り替えられているかどうかを検出するには、フラッター接続のみが必要です。このラッパーは、切り替えが発生した後に接続をチェックします。ただし、すべてのネットワーク変更を警告するわけではありません。エミュレータを使用している場合、機内モードを切り替えるのがインターネット接続を失う最も簡単な方法です。実際のデバイスを使用している場合は、データを使用してモバイルネットワークに接続していないことを確認する必要があります。
dennmat 2018

1
そのためのいくつかのオプションがあります。タイマーを使用して頻繁にテストするように上記を変更できます。または、タイマーユーティリティを使用して頻繁にテストします。参照:api.dartlang.org/stable/2.1.0/dart-async/Timer-class.html別のオプションは、送信するすべてのリクエストの前に接続をテストすることです。WebSocketのようなものを探しているようですが。とにかく頑張ってください
dennmat 2018

3
ウィジェットのdispose()関数でサブスクリプションをキャンセルするべ​​きではありませんか?私は、これは、ここのような他のStreamController例で行われている参照してください。stackoverflow.com/questions/44788256/updating-data-in-flutter
オレン

41

ここに画像の説明を入力してください

インターネット接続のリスナーとそのソースを示す完全な例。

クレジット:接続性と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();
}

Firebaseを介して、SDKは可能ですか?
LOG_TAG

@LOG_TAGこれにFirebaseを使用する必要はありません。
CopsOnRoad

1
@CopsOnRoadありがとうございます。あなたは私の時間を節約しました。
NimishaRanipa20年

Map _source = {ConnectivityResult.none:false}; ここで「false」を使用した理由
FarukAYDIN20年

@CopsOnRoadありがとうございます!私はこの方法を使用しましたが、この方法で初めてNoInternetConnectionが得られます!なぜ最初に私にNoneを与えるのですか?これは私のデバッグ出力です:connectivityResult.noneconnectivityResult.wificonnectivityResult.wifi。
FarukAYDIN20年

23

接続パッケージを使用するだけでは、インターネットが利用可能かどうかを判断するのに十分ではないことがわかりました。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;
    }
  }

このif (await DataConnectionChecker().hasConnection)部分はモバイル接続とwifi接続の両方で同じであり、おそらく別の機能に移動する必要があります。読みやすくするために、ここではそれを行いませんでした。

これは私の最初のスタックオーバーフローの答えです、それが誰かを助けることを願っています。


1
stackoverflowへようこそ。疑問に思っているのですが、await DataConnectionChecker().hasConnectionそもそも使用するよりも利点は何ですか?
ハーバート

2
唯一の理由は、IOSでは、接続パッケージが接続がないことをほぼ瞬時に通知できることです。data_connection_checkerパッケージを使用した場合、IOS上のアプリは、作成したhttpリクエストがタイムアウトするまで約10秒待機してから、falseを返す必要があります。ただし、これは場合によっては許容できる場合があります。接続パッケージは、WIFIまたはモバイルデータを使用しているかどうかも判断できます。ここでは知る必要はありませんが、知っておくと便利です。
abernee

これは、上記のコードの構文を少し変更するだけで完全に機能します。1.型は小文字であるため、Future <Bool>をfuture <bool>)に変更する必要があります。2.最後から4番目のreturnステートメントにセミコロン(;)を追加します。
TDM

TDMに感謝します、私はあなたの修正で答えを編集しました。
abernee

19

使用する

dependencies:
  connectivity: ^0.4.2

私たちがリソースから得たものは

      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;
      }

将来は私にとって少し問題があります、私たちは次のように毎回それを実装する必要があります:

check().then((intenet) {
      if (intenet != null && intenet) {
        // Internet Present Case
      }
      // No-Internet Case
    });

したがって、この問題を解決するために、このようなブールisNetworkPresentパラメーターを持つ関数を受け入れるクラスを作成しました。

methodName(bool isNetworkPresent){}

そしてユーティリティクラスは

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)

6

私は(私が思うに)この問題を確実に処理するパッケージを作成しました。

pub.devのパッケージ

GitHubのパッケージ

議論は大歓迎です。GitHubの課題トラッカーを使用できます。


以下の方法は信頼できる方法ではないと思います。


@Orenの答えに何かを追加したい:他のすべての例外をキャッチするキャッチをもう1つ追加するか(安全のために)、または例外タイプを完全に削除して、すべての例外を処理するキャッチを使用する必要があります。

ケース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;
}

またはさらに簡単...

ケース2:


try {
  await Firestore.instance
    .runTransaction((Transaction tx) {})
    .timeout(Duration(seconds: 5));
  hasConnection = true;
} catch (_) {
  hasConnection = false;
}

5

ウィジェット状態の基本クラスを作成しました

使用する代わりにState<LoginPage>使用するBaseState<LoginPage> 場合は、ブール変数isOnlineを使用します。

Text(isOnline ? 'is Online' : 'is Offline')

まず、接続プラグインを追加します。

dependencies:
  connectivity: ^0.4.3+2

次に、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;
  }
}

そして、あなたはこのようなあなたの状態でウィジェットをキャストする必要があります

@override
  void castStatefulWidget() {
    // ignore: unnecessary_statements
    widget is StudentBoardingPage;
  }

2
このクラスをどのように使用できますか?
DolDurma

@DolDurmaだけでは、それを追加し、<LoginPage>使用BaseState <LoginPage>そしてちょうどブール変数isOnline使う代わりに、国家のそれをインポート
amorenew

このコードでは、から変数を取得できませんwidget。例えば:RegisterBloc get _registerBloc => widget.registerBloc;私はこのエラーを取得error: The getter 'registerBloc' isn't defined for the class 'StatefulWidget'. (undefined_getter at lib\screens\fragmemt_register\view\register_mobile_number.dart:29):この実装を参照してくださいclass _FragmentRegisterMobileNumberState extends BaseState<FragmentRegisterMobileNumber> with SingleTickerProviderStateMixin { RegisterBloc get _registerBloc => widget.registerBloc;
DolDurma

@DolDurma私はこの情報が十分ではありませんので、問題はGitHubのサンプルなしでは何かわからない
amorenew

1
このレポをチェックして、私はどのように使用できるかを見せてくださいis_onlineコンソールにログインするために github.com/MahdiPishguy/flutter-connectivity-sample
DolDurma

3

@dennmattの回答に続いてInternetAddress.lookup、インターネット接続がオフの場合でも成功する結果が返される可能性があることに気付きました。シミュレーターから自宅の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は非同期インターネットチェックの前に設定されるため、理論的にcheckConnection()は、が短時間に複数回呼び出された場合hasConnection=true、1行に複数または1行に複数存在する可能性があることに注意hasConnection=falseしてください。@dennmattが意図的にそれを行ったかどうかはわかりませんが、私たちのユースケースでは副作用はありませんでした(setState同じ値で2回だけ呼び出されました)。


3

接続性:パッケージは実際のインターネット接続を保証しません(インターネットアクセスのないwifi接続である可能性があります)。

ドキュメントからの引用:

Androidでは、これはインターネットへの接続を保証するものではないことに注意してください。たとえば、アプリはWi-Fiにアクセスできますが、VPNまたはホテルのWi-Fiにアクセスできない場合があります。

あなたが本当にwwwインターネットへの接続をチェックする必要があるならば、より良い選択はでしょう

data_connection_checkerパッケージ


1

これが私の解決策です。インターネット接続とデータ接続をチェックします。気に入っていただければ幸いです。

まず、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"),
        ),
      ),
    );
  }
}

1

提案された解決策に問題がありました。使用lookupしても必ずしも期待値が返されるとは限りません。

これはDNSキャッシングが原因であり、呼び出しの値はキャッシュされ、キャッシュされた値を返す次の試行で適切な呼び出しを実行する代わりに行われます。もちろん、これはここでの問題です。接続が失われて呼び出したlookup場合でも、インターネットがあるかのようにキャッシュされた値が返される可能性があります。逆に、lookupnullが返された後にインターネットに再接続すると、その間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;
  }

の呼び出し_checkInternetAccesstimeout、完了するまでに最大で3秒かかります。DNSのいずれかに到達できる場合は、最初のDNSに到達するとすぐに、他のDNSを待たずに完了します(1つに到達するだけで十分です)。あなたがインターネットを持っていることを知っています)。へのすべての呼び出し_pingDnsは並行して行われます。

IPV4ネットワークではうまく機能しているようですが、IPV6ネットワークでテストできない場合(アクセスできない場合)でも機能するはずです。リリースモードのビルドでも機能しますが、このソリューションに問題がないかどうかを確認するために、アプリをAppleに送信する必要があります。

また、ほとんどの国(中国を含む)でも機能するはずです。機能しない場合は、ターゲット国からアクセスできるDNSをリストに追加できます。


1

私は最終的に(しぶしぶですが)この質問に対する以前の回答で@aberneeによって与えられた解決策に落ち着きました。私は常に、プロジェクトでできるだけ少ない外部パッケージを使用するようにしています。外部パッケージは、私が作成するソフトウェアの唯一の[潜在的な]障害点であることを知っています。したがって、このような単純な実装のためだけに2つの外部パッケージにリンクすることは、私にとって簡単ではありませんでした。

それにもかかわらず、私はアバニーのコードを取り、それをよりスリムでより賢明なものにするために修正しました。賢明なことは、彼が自分の機能で接続パッケージの電力を消費しているが、このパッケージから最も価値のある出力(つまりネットワークID)を返さないことによって内部的にそれを浪費していることを意味します。したがって、これがアバニーのソリューションの修正バージョンです。

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プロジェクトでこの非常に基本的な機能を利用するには、2つの外部パッケージにリンクする必要があるのは残念ですが、今のところ、これが最高だと思います。私は実際には接続パッケージよりもデータ接続チェッカーパッケージの方が好きですが、(これを投稿した時点で)前者には接続パッケージに必要な非常に重要なネットワーク識別機能がありませんでした。これが、私がこのアプローチをデフォルトにした理由です[一時的に]。


0

FlutterのConnectivityPackageを使用してコードを単純化しようとしているだけです。

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
}

ただし、Androidでのこれに関する問題は、Wi-Fiまたはモバイル経由で接続しているからといって、インターネットに接続しているわけではないということです。
Megadec

1
@Megadec悲しいことに、それが唯一の問題です:(
devDeejay 2010年

0

回答が遅れていますが、このパッケージを使用して確認してください。パッケージ名: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);

0

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);
}

詳細が必要な場合は、パッケージにアクセスしてください。 データ接続チェッカーパッケージ


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.