新項目的app,可經過內網和外網的服務器ip進行請求訪問,可是客戶提供了專業終端,終端在wifi狀況下走外網內網均可以,但關閉wifi則只能走4G專網,也就是隻能走內網。android
可前往個人小站查看:Android根據內網外網鏈接狀況配置服務器訪問IPshell
Android中能夠直接調用底層的shell,執行相應的命令,所以只須要執行ping命令便可。Android能夠經過 Process p = Runtime.getRuntime().exec(/system/bin/ping -c 1 -w 1 " + ip)
執行。
而後經過if (p.waitFor() == 0)
判斷是否ping通,這裏的兩個1
表示參數,第一個表示ping 1次,第二個表示操做1s即爲失敗。服務器
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.INTERNET" />
String outer_ip = "183.230.XXX.XXX"; // 服務器外網IP String inner_ip = "192.168.XXX.XXX"; // 服務器內網IP boolean outerIpAvilable = false; // 外網可用 boolean innerIpAvialable = false; // 內網可用
要在兩個ping結束以後,配置了ip以後才能作接下來的操做
。private void initNetworkConfig() { try { final int totalThread = 2; CountDownLatch countDownLatch = new CountDownLatch(totalThread); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(new PingNetwork(outer_ip, countDownLatch, false)); executorService.execute(new PingNetwork(inner_ip, countDownLatch, true)); countDownLatch.await(); // 等待兩者執行完畢 Log.d(TAG, "end"); if (innerIpAvialable && outerIpAvilable) Toast.makeText(this, "內外均可使用", Toast.LENGTH_SHORT).show(); else if (outerIpAvilable) Toast.makeText(this, "外網可以使用", Toast.LENGTH_SHORT).show(); else Toast.makeText(this, "內網可以使用", Toast.LENGTH_SHORT).show(); executorService.shutdown(); }catch (Exception e) { e.printStackTrace(); } }
class PingNetwork implements Runnable { String ip; // 須要ping的ip CountDownLatch countDownLatch; boolean isCheckInner; public PingNetwork(String ip, CountDownLatch countDownLatch, boolean isCheckInner) { this.ip = ip; this.countDownLatch = countDownLatch; this.isCheckInner = isCheckInner; } @Override public void run() { try { Process p = Runtime.getRuntime().exec("/system/bin/ping -c 1 -w 1 " + ip);// ping網址3次 // ping的狀態 final int status = p.waitFor(); if (status == 0) { Log.d(TAG, "ping onSuccess"); if (isCheckInner){ innerIpAvialable = true; outerIpAvilable = false; } else{ outerIpAvilable = true; innerIpAvialable = false; } } else { // 讀取ping的error內容,查看沒法ping通的緣由 InputStream errorStream = p.getErrorStream(); BufferedReader errIn = new BufferedReader(new InputStreamReader(errorStream)); StringBuilder sb = new StringBuilder(); String err = ""; while ((err = errIn.readLine()) != null) { sb.append(err); } Log.d(TAG, "result err : " + sb.toString()); Log.d(TAG, "ping onFailure"); } } catch (Exception e) { Log.d(TAG, "ping onFailure"); } finally { countDownLatch.countDown(); } } }
這裏在ping失敗時候能夠打印錯誤信息查看,還記得第一步是聲明權限,本人沒有聲明第二個權限,在這裏獲得了一個錯誤信息Pemission denied
,網上說什麼root的都有,其實否則。網絡
經過以上的實現,能夠實現經過內網外網鏈接狀況配置訪問服務器的ip,可是設想一下,若是在app啓動時,手機能夠訪問外網,因此程序配置了外網的ip(由於外網速度快),可是在使用的過程當中,關閉了外網訪問,好比說wifi,此時走了專網,即內網,則沒法再訪問服務器了。因此在切換網絡時,須要重新配置訪問ip。
所以,須要再app裏面經過廣播的方式,在android N(android 7)以前,能夠經過android.net.conn.CONNECTIVITY_CHANGE
廣播,能夠靜態註冊和動態註冊,然而在7以後,改廣播無效了,可使用如下方案替換。app
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); connectivityManager.requestNetwork(new NetworkRequest.Builder().build(), new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { super.onAvailable(network); LogUtil.d("網絡發生改變,更改配置"); NetworkUtils.initNetworkConfig(); } });
NetworkUtils.initNetworkConfig();
是我對上面經過ping配置ip的封裝。異步