0

I am looking for a solution to detect that a mobile device is really online and connected to the internet.

I have obviously tried the following method in an http interceptor:

if (navigator.connection.type != Connection.NONE) alert("you're online!")

The problem with that is that users who are connected to a wifi network that has no internet will get the message "you're online" although they have no internet. Why? Because in that case we have navigator.connection.type = Connection.WIFI.

Any help with a solution?

I can obviously ping google, but that's not so elegant and not sure google will appreciate I am overloading their server.

I've also thought of catching the responses of all my failed http requests, but not sure if based on that I can conclude if the user has internet or if the request failed for another reason.

Robycool
  • 1,104
  • 2
  • 14
  • 26
  • If you were using Firebase, they do have a pretty useful way to check the user's connection (which I'm using and seems to be working fine). Aside from that, there's [this](https://stackoverflow.com/a/16242703/7468384) question and answer about checking connection with Angular. – Gabriel Lovetro Sep 06 '17 at 18:19
  • 1
    Well there is no system event that will tell you if you _really_ have a _working_ connection. There is nothing else than trying an setting let say a timeout of 3000ms. You could use e GET call to some dummy resource on your server or like you said ping google - I think they can handle your traffic :) – David Sep 06 '17 at 21:36

4 Answers4

0

you can ping a server like website and check if you get any response then internet is connected otherwise not

Parth Godhani
  • 209
  • 3
  • 18
0

You can make Get call to an endpoint that you create on the server side which just responds with a 200 status with no data. I would only do that if a change in navigator.connection.type is detected. For the rest, I would suggest to implement the error callback function on each request that you make so that you can handle a unexpected connection loss or anything other than 200 and 201.

Mehdi
  • 2,263
  • 1
  • 18
  • 26
0

You can add EventListener whether users are Online or Offline .

You Need to add in platform ready as follows in your run function :

$ionicPlatform.ready(function(){
 document.addEventListener("offline", offlineCallBackFunction, false);
 document.addEventListener("online", onlineCallBackFunction, false);

})

Your callback functions as follows:

  function offlineCallBackFunction() {
          $ionicPopup.alert({
                title: "Internet Disconnected",
                content: "Internet is disconnected on your device."
            });

        }

    function onlineCallBackFunction() {
        $ionicPopup.alert({
            title: "Internet Connected",
            content: "Internet is connected on your device."
        })
        .then(function (result) {
            window.location.reload();
        });
    }

update

Above methods detects you are on a Network or not , but for you to check you have internet access or not by calling your own Server (API) Url .

Don't test with a host that isn't part of the actual request, especially if it is one you don't control. That is, if you want to test if the user can reach www.example.com, don't ping www.google.com. Your attempt might be taken as a malicious attack, especially if your app became popular.

Krsna Kishore
  • 8,233
  • 4
  • 32
  • 48
  • Unfortunately this works the same way as navigator.connection.type != Connection.NONE. If I connect to a wifi network without the internet, I get the message "Internet Connected". – Robycool Sep 07 '17 at 07:12
  • @Robycool , got it , this part tells you that you are connected to the network , try to access your api `URL` , if it failed then you don't have a internet access, rather than pinging `Google` – Krsna Kishore Sep 07 '17 at 07:18
0

As @David stated, there is no system event that will tell you if you really have a working internet connection.

The logic

Create a boolean vm.isInternetUp and assume the user is connected. There are three reasons why a user can be disconnected:

  1. If an offline event is fired by the browser, meaning there is no wifi, 3g or ethernet connection
  2. If the device is connected to a wifi channel, but the wifi channel has no internet.
  3. There could also be a 3G/ethernet connection without internet, but that was not relevant in our case (not included in this post).

Now we just need to detect when one of these conditions happen, which turns vm.isInternetUp to false. When that flag is turned to offline, we start a loop with a http request to our API until we get a positive response.

It's quite cumbersome, but in this way we don't overload our server with continuous http requests to check the status of the internet connection. Only one http will reach the server when the user gets back online.

The Code

There are different ways to implement this (look at @webruster's answer with online/offline events). I chose using interceptors because it best fits my specific needs.

  vm.isInternetUp = true //assume internet is up at startup
  var interceptor = {
    request: function(config) {
      return vm.checkForInternet(config);
    },
    responseError: function(reject){
      return vm.handleBadWifi(reject)
    }
  }

For reason 1, I use angular's http request interceptor to check at every request whether we're connected to a wifi. If not, it means we're offline.

  vm.checkForInternet = function(config) {

    if (angular.isUndefined(window.Connection)) {
      // The project is run in a web browser so window.Connection doesn’t exist. Assume we have internet.
      console.log("window.Connection doesn't exist")
      return config;
    }
    //if there is no internet
    if (navigator.connection.type === Connection.NONE || !vm.isInternetUp) {
      vm.isInternetUp = false
      vm.reconnect();
      }
      else {
        console.log("connected but bad wifi")
      }
    }
    return config;
  }

For reason 2, I use $http responseError interceptor intercepting all http requests. As the documentation states, reject.status = -1 usually means the request was aborted; we conclude from that that there is no internet connection.

  vm.handleBadWifi = function(reject) {
      if (navigator.connection.type == Connection.WIFI && reject.status == -1) {
        vm.isInternetUp = false
        vm.checkForInternet(); //this will launch reconnection loop until connected again
      }  
      return $q.reject(reject);      
  }

And finally the reconnection loops that stops as soon as we get a positive request. It's quite long because we cannot use angular's $http service as we are in an $http interceptor. Using $http would cause a circular dependency.

  vm.reconnect = function() {
    //Restart only if we were previously disconnected and after checking that we really have the internet
    if (!vm.isInternetUp & !vm.reconnecting) {
      console.log("attempting http call")
      vm.reconnecting = true;
      //backend-host is only pinged if internet was previously disconnected. In this way it does not overload the server.
      //we don't use $http because that would induce a circular dependency (we're in an $http interceptor here). As this is a pure js http call this request will not be intercepted.
      pureJsHttpGet(backendHost + 'projects/',vm.reconnectSuccess,vm.reconnectError)
    }           
  }
  vm.reconnectSuccess = function () {
    vm.isInternetUp = true;
    vm.reconnecting = false;  
  }
  vm.reconnectError = function (error) {
    $timeout(function () {
      vm.reconnecting = false;
      vm.checkForInternet();
    },3000)
    console.error("Did not manage to find an internet connection. Retrying in 3 sec", error)  
    if (navigator.connection.type === Connection.WIFI){
      //create a fake reject error so that the wifi errorhandler knows the request failed
      var reject = {status:-1}
      vm.handleBadWifi(reject)     
    }
  }
  function pureJsHttpGet(theUrl, successCallback, errorCallback){
      var xmlHttp = new XMLHttpRequest();
      xmlHttp.onreadystatechange = function() { 
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200) 
            successCallback(xmlHttp.responseText);
          else if (xmlHttp.readyState == 4 && xmlHttp.status == 0)
            errorCallback(xmlHttp)
      }
      xmlHttp.open("GET", theUrl, true); // true for asynchronous 
      xmlHttp.send(null);
  }
Robycool
  • 1,104
  • 2
  • 14
  • 26