Android根據(jù)內(nèi)網(wǎng)外網(wǎng)連接情況配置服務(wù)器訪問(wèn)IP

新項(xiàng)目的app,可通過(guò)內(nèi)網(wǎng)和外網(wǎng)的服務(wù)器ip進(jìn)行請(qǐng)求訪問(wèn),但是客戶提供了專業(yè)終端,終端在wifi情況下走外網(wǎng)內(nèi)網(wǎng)都可以,但關(guān)閉wifi則只能走4G專網(wǎng),也就是只能走內(nèi)網(wǎng)。

可前往我的小站查看:Android根據(jù)內(nèi)網(wǎng)外網(wǎng)連接情況配置服務(wù)器訪問(wèn)IP

方案

Android中可以直接調(diào)用底層的shell,執(zhí)行相應(yīng)的命令,因此只需要執(zhí)行ping命令即可。Android可以通過(guò) Process p = Runtime.getRuntime().exec(/system/bin/ping -c 1 -w 1 " + ip)執(zhí)行。
然后通過(guò)if (p.waitFor() == 0)判斷是否ping通,這里的兩個(gè)1表示參數(shù),第一個(gè)表示ping 1次,第二個(gè)表示超過(guò)1s即為失敗。

完整實(shí)現(xiàn)

  1. 首先聲明權(quán)限,這一步非常重要,在AndroidManifes文件中
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
  1. 維持幾個(gè)全局變量
    String outer_ip = "183.230.XXX.XXX"; // 服務(wù)器外網(wǎng)IP
    String inner_ip = "192.168.XXX.XXX"; // 服務(wù)器內(nèi)網(wǎng)IP

    boolean outerIpAvilable = false;  // 外網(wǎng)可用
    boolean innerIpAvialable = false; // 內(nèi)網(wǎng)可用
  1. 開啟兩個(gè)線程去ping兩個(gè)ip,并通過(guò)CountDownLatch控制同步。因?yàn)?code>要在兩個(gè)ping結(jié)束之后,配置了ip之后才能做接下來(lái)的操作。
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(); // 等待二者執(zhí)行完畢
            Log.d(TAG, "end");
            if (innerIpAvialable && outerIpAvilable)
                Toast.makeText(this, "內(nèi)外都可使用", Toast.LENGTH_SHORT).show();
            else if (outerIpAvilable)
                Toast.makeText(this, "外網(wǎng)可使用", Toast.LENGTH_SHORT).show();
            else
                Toast.makeText(this, "內(nèi)網(wǎng)可使用", Toast.LENGTH_SHORT).show();
            executorService.shutdown();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
  1. 實(shí)現(xiàn)ping的異步線程,
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網(wǎng)址3次
                // ping的狀態(tài)
                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內(nèi)容,查看無(wú)法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失敗時(shí)候可以打印錯(cuò)誤信息查看,還記得第一步是聲明權(quán)限,本人沒(méi)有聲明第二個(gè)權(quán)限,在這里得到了一個(gè)錯(cuò)誤信息Pemission denied,網(wǎng)上說(shuō)什么root的都有,其實(shí)不然。

完善

通過(guò)以上的實(shí)現(xiàn),可以實(shí)現(xiàn)通過(guò)內(nèi)網(wǎng)外網(wǎng)連接情況配置訪問(wèn)服務(wù)器的ip,但是設(shè)想一下,如果在app啟動(dòng)時(shí),手機(jī)可以訪問(wèn)外網(wǎng),所以程序配置了外網(wǎng)的ip(因?yàn)橥饩W(wǎng)速度快),但是在使用的過(guò)程中,關(guān)閉了外網(wǎng)訪問(wèn),比如說(shuō)wifi,此時(shí)走了專網(wǎng),即內(nèi)網(wǎng),則無(wú)法再訪問(wèn)服務(wù)器了。所以在切換網(wǎng)絡(luò)時(shí),需要從新配置訪問(wèn)ip。
因此,需要再app里面通過(guò)廣播的方式,在android N(android 7)之前,可以通過(guò)android.net.conn.CONNECTIVITY_CHANGE廣播,可以靜態(tài)注冊(cè)和動(dòng)態(tài)注冊(cè),然而在7之后,改廣播無(wú)效了,可以使用以下方案替換。

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("網(wǎng)絡(luò)發(fā)生改變,更改配置");
                        NetworkUtils.initNetworkConfig();
                    }
                });

NetworkUtils.initNetworkConfig();是我對(duì)上面通過(guò)ping配置ip的封裝。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容