前言
三月份新入职的公司,公司的主要业务是只能电视应用,由于公司战略需要,准备做一个tvos,里面包含有设置的系统应用,本人分到的任务是wifi这一块开发。由于之前接手的都是移动端的开发,对于wifi这一块几乎没有接触过,所以分享出来,希望我踩过的坑,大家能避免。
正文
wifi扫描:
首先,要对设备的网络情况就行修改,就要获得相应的权限:
复制代码
然后,接收网络变化的广播:
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,进行相应的处理:
@Overridepublic 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,
//开启或者关闭WIFIpublic void openWifi(boolean isEnable) { if (!isEnable) { removeConnecting(); } wifiManager.setWifiEnabled(isEnable);}复制代码
如果wifi以及打开就开始扫描wifi信号:
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_ACTION
的广播。通过List<ScanResult> scanResults = wifiManager.getScanResults();
获取扫描结果,接下来看下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) { ListexistingConfigs = 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名称一样的时候,就不好处理,这边的处理是直接忽略一个,如果有大神有好的方案,欢迎留言,大家一起讨论下