Android設備wifi開發

前言

       三月份新入職的公司,公司的主要業務是隻能電視應用,因爲公司戰略須要,準備作一個tvos,裏面包含有設置的系統應用,本人分到的任務是wifi這一塊開發。因爲以前接手的都是移動端的開發,對於wifi這一塊幾乎沒有接觸過,因此分享出來,但願我踩過的坑,你們能避免。android

正文

      wifi掃描:bash

首先,要對設備的網絡狀況就行修改,就要得到相應的權限:網絡

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /><!-- 容許程序改變網絡連接狀態 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><!--容許程序訪問訪問WIFI網絡狀態信息  -->複製代碼

     而後,接收網絡變化的廣播:ide

public class WifiBroadcastReceiver extends BroadcastReceiver {
    private IntentFilter filter;
    private Context context;
    private WifiStateChangeListener wifiStateChangeListener;


    public WifiBroadcastReceiver(Context context) {
        this.context = context;
        filter = new IntentFilter();
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);//wifi開關變化廣播
        filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);//熱點掃描結果通知廣播
        filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);//—熱點鏈接結果通知廣播
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);  //—網絡狀態變化廣播(與上一廣播協同完成鏈接過程通知)
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        context.registerReceiver(this, filter);
    }


    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (null != wifiStateChangeListener) {
            wifiStateChangeListener.onWifiChange(intent);
        }
    }

    public void unRegister() {
        context.unregisterReceiver(this);
    }


    public void setWifiStateChangeListener(WifiStateChangeListener wifiStateChangeListener) {
        this.wifiStateChangeListener = wifiStateChangeListener;
    }

    public interface WifiStateChangeListener {
        /**
         */
        void onWifiChange(Intent action);
    }

}複製代碼

經過不一樣廣播的action,進行相應的處理:測試

@Override
public void onWifiChange(Intent action) {
    switch (action.getAction()) {
        case WifiManager.WIFI_STATE_CHANGED_ACTION:
            checkWfiState(action);
            break;
        case WifiManager.SCAN_RESULTS_AVAILABLE_ACTION:
            getScanResult();
            break;
        case WifiManager.SUPPLICANT_STATE_CHANGED_ACTION:
            int error = action.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0);
            if (WifiManager.ERROR_AUTHENTICATING == error) {
                toastFail();
            } else {
                checkWifiConnectState(action);
            }
            break;
        default:
            //網線
            if (NetInfoUtil.isEthernet()) {
                finish();
            }
            break;

    }

}
複製代碼

接下來打開wifi,ui

//開啓或者關閉WIFI
public void openWifi(boolean isEnable) {
    if (!isEnable) {
        removeConnecting();

    }
    wifiManager.setWifiEnabled(isEnable);
}複製代碼

若是wifi以及打開就開始掃描wifi信號:this

private void checkWfiState(Intent intent) {
//獲取當前wifi的狀態
    int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
            WifiManager.WIFI_STATE_DISABLED);
    switch (wifiState) {
        case WifiManager.WIFI_STATE_DISABLED:
            //wifi已關閉
            connectState = WifiConnectState.NONE;
            wifiSwitchView.setEnabled(true);
            wifiSwitchView.setWifiOpened(false);
            stopScanWifi();
            break;
        case WifiManager.WIFI_STATE_ENABLED:
            //wifi已打開
            startScanWifi(true);
            wifiSwitchView.setEnabled(true);
            wifiSwitchView.setWifiOpened(true);
            break;
        case WifiManager.WIFI_STATE_ENABLING:
            wifiSwitchView.setEnabled(false);
            //wifi正在打開
            break;
        case WifiManager.WIFI_STATE_DISABLING:
            wifiSwitchView.setEnabled(false);
            //wifi正在關閉
            break;
        default:
            break;
    }
}複製代碼

開始掃描wifi:加密

/**
 * 開始掃描Wifi
 */
private void startScanWifi(boolean isLoading) {
    if (isLoading) {
        showLoadingDialog("");
    }
    wifiManager.startScan();
}複製代碼

Wifi掃描成功以後,會發出一個WifiManager.SCAN_RESULTS_AVAILABLE_ACTIONspa

的廣播。經過List<ScanResult> scanResults = wifiManager.getScanResults();code

獲取掃描結果,接下來看下ScanResult這個類,其中SSID,表示是wifi的名稱。capabilities描述了wifi的加密方式等信息,能夠經過以下方式判斷wifi的加密方式:

if (model.capabilities.contains("WPA") || model.capabilities.contains("wpa")) {
    encryptType = TYPE_ENCRYPT_WPA;
} else if (model.capabilities.contains("WEP") || model.capabilities.contains("wep")) {
    encryptType = TYPE_ENCRYPT_WEP;
} else {
    encryptType = "";
}複製代碼

不一樣的加密方式,鏈接的處理方式第不同的。level是表示wifi的信號強度,通常是個負數,越大表示信號越強。


wifi鏈接:

首先判讀wifi是否已保存,若是以及保存,那麼不須要輸入密碼直接鏈接,經過以下方法判讀wifi是否保存:

private WifiConfiguration getExistConfig(String ssid) {
    List<WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
    if (!CollectionUtil.isEmpty(existingConfigs)) {
        for (WifiConfiguration existingConfig : existingConfigs) {
            if (TextUtil.isEquals(existingConfig.SSID, ssid))
                return existingConfig;
        }

    }

    return null;

}複製代碼

wifiManager.getConfiguredNetworks()會把全部已經保存的wifi,返回,若是掃描出的wifi嗎名稱,可以在.getConfiguredNetworks()找到證實是已保存的。經過以下方法鏈接wifi:

int netId = wifiManager.addNetwork(config);
//WifiManager的enableNetwork接口,就能夠鏈接到netId對應的wifi了
//其中boolean參數,主要用於指定是否須要斷開其它Wifi網絡
wifiManager.enableNetwork(netId, true);複製代碼

若是wifi沒有保存,那麼有本身構造WifiConfiguration,以下:

public WifiConfiguration createWifiConfig(WifiScanResultVM wifiScanResultVM) {
    //初始化WifiConfiguration
    WifiConfiguration config = new WifiConfiguration();

    config.SSID = wifiScanResultVM.getSsid();

    //不須要密碼的場景
    String password = wifiScanResultVM.getPassWord();
    if (!wifiScanResultVM.isEncrypt()) {
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
        //以WEP加密的場景
    } else if (TextUtil.isEquals(wifiScanResultVM.getEncryptType(), WifiScanResultVM.TYPE_ENCRYPT_WEP)) {
        int i = password.length();
        if (((i == 10 || (i == 26) || (i == 58))) && (password.matches("[0-9A-Fa-f]*"))) {
            config.wepKeys[0] = password;
        } else {
            config.wepKeys[0] = "\"" + password + "\"";
        }
        //以WPA加密的場景,本身測試時,發現熱點以WPA2創建時,一樣能夠用這種配置鏈接
    } else if (TextUtil.isEquals(wifiScanResultVM.getEncryptType(), WifiScanResultVM.TYPE_ENCRYPT_WPA)) {
        config.preSharedKey = "\"" + password + "\"";
        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
    }

    return config;
}複製代碼

須要區分不一樣的加密方式,鏈接過程當中會屢次發出,WifiManager.SUPPLICANT_STATE_CHANGED_ACTION

這個廣播,處理以下:

int error = action.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0);
if (WifiManager.ERROR_AUTHENTICATING == error) {
    toastFail();
} else {
    checkWifiConnectState(action);
}複製代碼


/**
     * wifi切換鏈接
     *
     * @param intent
     */
    public void checkWifiConnectState(Intent intent) {
        SupplicantState supplicantState = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
        if (null != supplicantState) {
            switch (supplicantState) {
                case DISCONNECTED:
                    connectState = WifiConnectState.NONE;
                    getScanResult();
                    break;
                case COMPLETED:
//                    if (currentData != null) {
//                        XLog.e("SSID", "checkWifiConnectState" + currentData.getSsid());
//                    }
                    getScanResult();
                    connectState = WifiConnectState.CONNECTED;
                    break;
            }
            return;
        }
    }複製代碼

還有一個問題,如何判斷當前正在鏈接的是哪一個wifi,以下:

private String getCurrentSsid() {
//        XLog.e("SSID", "getCurrentSsid: ");
        if (connectState != WifiConnectState.CONNECTED) {
//            XLog.e("SSID", " WifiConnectState.CONNECTED: " + connectState.name());
            return "";
        }
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        if (wifiInfo != null) {
//            XLog.e("SSID", "wifiInfo" + wifiInfo.getSSID());
            return wifiInfo.getSSID();

        }
//        XLog.e("SSID", "null null null ");
        return "";
    }複製代碼

經過拿到當前wifi的鏈接信息進行比對,有個問題值得注意,當前wifi正在鏈接時,

WifiInfo wifiInfo = wifiManager.getConnectionInfo();複製代碼

返回的也是有值得,須要注意下。

未填的坑:

當有兩個wifi名稱同樣的時候,就很差處理,這邊的處理是直接忽略一個,若是有大神有好的方案,歡迎留言,你們一塊兒討論下

相關文章
相關標籤/搜索