我們知道,當手機上顯示網絡連接配接成功時,并不一定可以真的上網。常見的情況是,連上路由後需要進行跳轉登入,或者幹脆路由連接配接到網絡的端口壞掉。是以在進行網絡通訊前,可能需要确認網絡是否真正聯通。
經典方法
一種常用的方法,也是沿用pc機上檢視網絡是否聯通的方法,就是使用ping指令。要注意ping在windows上和linux上的參數意義是不一樣的。使用-c來确定ping的次數。adb shell進入android環境,輸入指令,效果如下。這裡www.a.shifen.com是百度為了防止攻擊而設定的殼位址,可以忽略。
shell環境中的ping
那麼現在要做的就是在android代碼裡使用ping指令,代碼如下:
Runtime runtime = Runtime.getRuntime();
try {
Process p = runtime.exec("ping -c 3 www.baidu.com");
int ret = p.waitFor();
Log.i("Avalible", "Process:"+ret);
} catch (Exception e) {
e.printStackTrace();
}
然後我們來看下不同網絡狀态下代碼的執行效果:
連通的移動資料網絡下:
連通的移動資料網絡下
在需要網頁認證的wifi下:
在需要網頁認證的wifi下
在wifi打開但沒有網絡連接配接,資料也不可用的狀态下:
在wifi打開但沒有網絡連接配接,資料也不可用的狀态下
在不可用wifi下:
在不可用wifi下
在可用wifi下:
在可用wifi下
基本上隻要判斷是否是0即可,若是0則網絡真正可用。
Android 6.0以上可用方法
在API 21增加了一個類NetworkCapabilities,其中有很多對于網絡性能的描述,可以通過ConnectivityManager獲得描述目前網絡的NetworkCapabilities。而在API23中,增加了一個描述NET_CAPABILITY_VALIDATED。文檔中對其描述如下:
Indicates that connectivity on this network was successfully validated. For example, for a network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully detected.
實驗表明,當NetworkCapabilities的描述中有VALIDATED這個描述時,此網絡是真正可用的。使用如下代碼獲得目前網絡的capabilities:
NetworkCapabilities networkCapabilities = mConnectivityManager.getNetworkCapabilities(mConnectivityManager.getActiveNetwork());
Log.i("Avalible", "NetworkCapalbilities:"+networkCapabilities.toString());
可以看到代碼非常簡單,将對于NetworkCapabilities的描述列印出來,不同網絡狀态下結果如下:
在可聯通的wifi下,可看到出現了VALIDATED的标記:
在可聯通的wifi下
在需要認證的wifi下,可以看到相應區域沒有VALIDATED的标記:
在需要認證的wifi下
在不可上網的wifi下,可以看到也沒有VALIDATED的标記:
在不可上網的wifi下
在移動資料下,可以看到VALIDATED又出現了:
在移動資料下
是以可以通過判斷這個标記是否存在來判斷網絡的連通性。通過如下調用來判斷标記存在與否:
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
可惜隻能6.0以上使用,目前還是又很多6.0下的手機在使用的,是以經典方法還是很重要。
http協定
其實檢視網絡連接配接是否成功的本質,就是實際去連下,看看能不能連到。是以理論上任何網絡通訊協定都可以來處理這件事。但實際上,開發中大多使用經典方法是有道理的。因為ping指令本身就是為了檢視網絡連通狀況而存在。而使用http協定的話,不但資料包會較大、使用較複雜,很多情況也沒法處理。下面來簡單地用Get去通路url看看會發生什麼。代碼如下:
HttpURLConnection httpConn = null;
InputStream inputStream = null;
int respondcode = -1;
try{
URL url = new URL("http://www.baidu.com");
httpConn = (HttpURLConnection)url.openConnection();
httpConn.setRequestMethod("GET");
respondcode = httpConn.getResponseCode();
Log.i("Avalible", "HttpURLConnection1:"+respondcode+" "+httpConn.getHeaderField("Location"));
url = new URL(httpConn.getHeaderField("Location"));
httpConn = (HttpURLConnection)url.openConnection();
httpConn.setUseCaches(false);
httpConn.setRequestMethod("GET");
respondcode = httpConn.getResponseCode();
Log.i("Avalible", "HttpURLConnection2:"+respondcode+" "+httpConn.getHeaderField("Location"));
}catch(Exception e){
e.printStackTrace();
}
由于可能會發生重定向,是以進行兩次http請求,并且将重定向的url列印出來檢視。不同網絡下結果如下:
移動資料流量。首先進行了一次跳轉,第二次傳回200成功:
移動資料流量
可連通wifi下,完全一樣:
可連通wifi下
需要認證wifi下,傳回200,但實際上并沒有确認可連通www.baidu.com,隻是連接配接到了需要登入的位址。是以實際上是沒法通過傳回值來判斷究竟能否上網的:
需要認證wifi下
而在無法上網的情況下,是直接報錯的:
無法上網的情況下
是以相對來說,使用http協定,處理的過程更加複雜,傳回結果不夠明确,相對不适合用來判斷網絡是否連通。