What if your Android user doesn’t have access to the Internet

Source: Unsplash

Did you ever try to be sure that your android users have access to the Internet? I’m not talking about detection if user is connected to some network (WIFI or mobile), I am talking about situations where user is connected to the WIFI but doesn’t have access to the public Internet. Well, that was a challenge! I wanted to be sure, before making any API calls, that device is connected to some network interface and that he has access to the internet, if he doesn’t have access to the internet but is connected to the network interface I would threat that situation the same as if he wasn’t connected at all. That was my goal and that is something that I wanted to do. Why? Because it is hard to define a timeout for API calls since app needs to be used when a user has bad network. In that situation requests will be longer, and when user doesn’t have internet but is connected to the network my request is longggg before a timeout is reached.

What I had

I had a method that was used for checking if a device is connected to the internet, this method bellow.

public static boolean isNetworkAvailable() {  
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

Do you know what getActiveNetworkInfo method does? We could check the android official documentation for that.

Returns details about the currently active default data network. When connected, this network is the default route for outgoing connections. You should always check isConnected() before initiating network traffic. This may return null when there is no default network. Android official documentation

So, if we read that description more carefully we will find out that this method will just tell us if a device is connected to some network interface, but will not tell us if a device is connected to the Internet. Long story short this method does not do what I thought it did. Ok, it seems that I will have to make some update to that method.

Note that having an active network interface doesn’t guarantee that a particular networked service is available. Networks issues, server downtime, low signal, captive portals, content filters and the like can all prevent your app from reaching a server. For instance you can’t tell for sure if your app can reach Twitter until you receive a valid response from the Twitter service. Stack Overflow

It’s time to make a mess in my method

I faced that challenge and as with everything else I did a little research about a problem and potential solutions. Stack Overflow had few discussions exactly about my problem! Oh, yea! I will for sure find a solution here, but then I got a slap in my face. I checked android official documentation with hope that I will find a solution there, come on, it’s google if they don’t know who knows?? Well, again I got a slap in my face. So, in this article, I will go through all solutions that I found.

I tried to use ping command, with code below:

public static boolean isNetworkAvailable () {

Runtime runtime = Runtime.getRuntime();
try {

Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
int exitValue = ipProcess.waitFor();
return (exitValue == 0);

} catch (IOException e){
e.printStackTrace();
} catch (InterruptedException e){
e.printStackTrace();
}
return false;
}
When you run a process within your app, you only are granting the app’s limited permissions to the process. So if ping requires root level permission (on the specific device), that may also be the reason why it does not work. It is ultimately up to the OEM of how they customized Android. Stack Overflow

It’s nice, it’s fast and it will do the work, but there is a problem with that command; it does not work on all devices. I can’t use it if that means that some users will be blocked because this method will return false on devices where it does not work. It looks like I need to try another approach.

Next approach

public static boolean isNetworkAvailable () {  
boolean success = false;
try {
URL url = new URL("https://google.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(10000);
connection.connect();
success = connection.getResponseCode() == 200;
} catch (IOException e) {
e.printStackTrace();
}
return success;
}

Or, more efficient way

public static boolean isNetworkAvailable (Context context) {  
if (connectedToTheNetwork(context)) {
try {
HttpURLConnection urlc = (HttpURLConnection)
(new URL("http://clients3.google.com/generate_204")
.openConnection());
urlc.setRequestProperty("User-Agent", "Android");
urlc.setRequestProperty("Connection", "close");
urlc.setConnectTimeout(1500);
urlc.connect();
return (urlc.getResponseCode() == 204 &&
urlc.getContentLength() == 0);
} catch (IOException e) {
Log.e(TAG, "Error checking internet connection", e);
}
} else {
Log.d(TAG, "No network available!");
}
return false;
}
With this modification we will not need to fetch entire google page. Stack Overflow

I am not sure which approach would be better, also I don’t want to make a request to check the internet before making a request :) There is no point in making two requests every time since my app has many requests per session. I need to point out that it is bad to ping google since it is banned in some countries, so your app will not be able to detect internet connection in some countries. Better way of doing that is to ping your server.

What do you think? Which approach do you use? Is there any better way to solve this problem or do I need to use one of the solutions mentioned above?


Originally published at itworkslocal.ly on July 24, 2016.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.