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名称同样的时候,就很差处理,这边的处理是直接忽略一个,若是有大神有好的方案,欢迎留言,你们一块儿讨论下

相关文章
相关标签/搜索