Android自动连接指定的WiFi热点
Android自动连接指定的WiFi热点
“Android自动连接指定的WiFi热点”,看上去这是个再基础不过的功能了。很多人都觉得很简单,网上也有大量的资料。但在以Android作为底层系统的硬件设备的连接上,特别针对我们自主开发的轻推投屏盒子为例,这个技术是比较重要的一个点。接下来我就以轻推投屏盒子为例,讲讲Android系统连接WiFi热点的一些难点。
推投屏盒子有两张无线网卡,一个负责对外上网,一个负责对内提供AP局域网。这样的设计是为了在没有外网的环境下也能够实现投屏功能(避免了很多市面上的投屏盒子的缺点。比如必须连接WiFi,并且不支持8021x/eap的WiFi连接),通过连接轻推投屏盒子的AP,实现某些公司需要的公司内网认证。
好了,接下来进入正题,上网WiFi我们使用Android系统的提供WiFi模块管理——WiFiManager。
WiFiManager:是系统提供给开发者使用的系统服务管理类,WifiManager会调用service和framework层, 驱动层进行函数调用,
然后驱动层会回调至上层, 以广播的形式实现通知。简单来说就是,只需要使用WifiManager进行函数操作完成UI, 监听对应的广播消息, 就可完成功能了。
笔者所用到方法:
WiFiManager.startScan():开始扫描WiFi,扫描结果通过广播通知
WiFiManager.disconnect():断开网络WiFi
WiFiManager.addNetwork(WifiConfiguration config):添加WiFi配置,返回networkId
WiFiManager.enableNetwork(networkId, true):允许与以前配置的网络相关联,并尝试连接WiFi
WiFiManager.getScanResults():获取设备缓存的扫描结果,这里部分手机的缓存会很少,跟实际扫描结果不一致,这个时候需要调用一次扫描更新缓存
第一步:获取WiFiManager
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
第二步:获取扫描结果缓存
ScanResult.SSID 表示WiFi名,这里需要注意有"",如果界面需要显示,那么得把这个去掉,连接的时候这个得保留才行
ScanResult.BSSID mac,表示WiFi的唯一标识,
ScanResult.frequency 表示WiFi的频率
ScanResult.level 表示WiFi的信号强度,这里为负数,越大表示信号越好
List<ScanResult> scanResults = wifiManager.getScanResults();
第三步:连接WiFi
/** * wif连接 * * @param scanResult ScanResult * @param userName String eap连接需要的用户名 * @param pass String 密码 * @return 操作结果 */ public boolean connectionWifi(ScanResult scanResult,String userName,String pass) { WifiConfiguration config = getWifiConfig(ScanResult scanResult,String userName,String pass); networkId = wifiManager.addNetwork(config); wifiManager.saveConfiguration(); return wifiManager.enableNetwork(networkId, true); }
工具方法
判断WiFi类型
/** * 获取wifi安全类型. * * @param result ScanResult * @return 0 */ public static int getSecurity(ScanResult result) { if (null != result && null != result.capabilities) { if (result.capabilities.contains("WEP")) { return SECURITY_WEP; } else if (result.capabilities.contains("PSK")) { return SECURITY_PSK; } else if (result.capabilities.contains("EAP")) { return SECURITY_EAP; } } return SECURITY_NONE; }
获取wif连接配置
/** * 获取wif连接配置 * * @param scanResult ScanResult * @return */ public WifiConfiguration getConfig(ScanResult scanResult,String userName,String pass){ WifiConfiguration config = new WifiConfiguration(); switch(getSecurity(scanResult)){ case SECURITY_NONE: initOpenConfig(config); break; case SECURITY_WEP: initWepConfig(scanResult,config,pass); break; case SECURITY_PSK: initPskConfig(scanResult,config,pass); break; case SECURITY_EAP: initEapConfig(scanResult,config,userName,pass); break; } } /** * 初始化公开类型WiFi * * @param config WifiConfiguration */ private void initOpenConfig(WifiConfiguration config){ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); } private void initWepConfig(ScanResult scanResult, WifiConfiguration config,String pass) { config.hiddenSSID = true; //安全认证协议 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); //身份验证算法 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); config.wepTxKeyIndex = 0; if (isHexWepKey(pass)) config.wepKeys[0] = wifiConnDO.getPassword();//密码 else config.wepKeys[0] = convertToQuotedString(pass);//密码 } private void initPskConfig(ScanResult scanResult, WifiConfiguration config,String pass) { config.hiddenSSID = true; //公认安全协议 config.allowedProtocols.set(WifiConfiguration.Protocol.RSN); config.allowedProtocols.set(WifiConfiguration.Protocol.WPA); //安全认证协议 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); //密码为WPA config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); //公认的的公共组密码 config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); //身份验证算法 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); config.preSharedKey = convertToQuotedString(pass);//密码 config.status = WifiConfiguration.Status.ENABLED; } private void initEapConfig(ScanResult scanResult, WifiConfiguration config,String userName,String pass) { config.hiddenSSID = false; //安全认证协议 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);//企业级WiFi的相关信息输入配置 WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); enterpriseConfig.setIdentity(wifiConnDO.getUsername());//用户身份 enterpriseConfig.setPassword(wifiConnDO.getPassword());//用户密码 enterpriseConfig.setAnonymousIdentity("");//匿名身份 enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.PEAP);//EAP类型 enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE); config.enterpriseConfig = enterpriseConfig; } static boolean isHexWepKey(@Nullable String wepKey) { final int passwordLen = wepKey == null ? 0 : wepKey.length(); return passwordLen != 0 && (passwordLen == 10 || passwordLen == 26 || passwordLen == 58) && wepKey.matches("[0-9A-Fa-f]*"); } static String convertToQuotedString(@NonNull String string) { if (TextUtils.isEmpty(string)) return ""; final int lastPos = string.length() - 1; if (lastPos < 0 || (string.charAt(0) == '"' && string.charAt(lastPos) == '"')) return string; return "\"" + string + "\""; }
在我们的实际使用中发现,公司的WiFi有些问题,已经连接过的再次连接的时候会出现连不上的问题,通过对WifiStateMachine的各种日志分析之后发现是我们公司的认证服务有些异常,但这不是我们负责的,所以我们这边采取的方案是,移除配置,然后添加新的配置,问题成功解决。
获取已经系统保存的WiFi配置信息和新的连接方法
protected boolean connectionWifi(WifiConnDO wifiConnDO) { //获取已保存的WiFi配置 WifiConfiguration config = getSaved(wifiConnDO); int networkId; if (config != null) { networkId = config.networkId; //移除以保存的配置并保存操作 wifiManager.removeNetwork(networkId); wifiManager.saveConfiguration(); } //获取WiFi配置 config = getWifiConfig(wifiConnDO);// config.BSSID = wifiConnDO.getBssid(); //添加并保存配置 networkId = wifiManager.addNetwork(config); wifiManager.saveConfiguration(); //使用WiFi return wifiManager.enableNetwork(networkId, true);; }private WifiConfiguration getSaved(ScanResult result) { List<WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks(); if (existingConfigs == null) { return null; } for (WifiConfiguration existingConfig : existingConfigs) { if (existingConfig.SSID.equals(result.SSID)) { return existingConfig; } } return null; }
关于连接WiFi的广播部分这里就不做过多说明了,与其他技术博客的一样即可。
整个过程中我们遇到很多问题,诸如上网芯片支持的频道过少发现不了公司5GWiFi的信道,公司WiFi上网定期会断之后重新连接会切到其他BSSID的同名WiFi导致上网速度慢…
有疑问和指教的地方请私联:long.zhao@cisdi.com.cn
更多相关文章
- 【阿里云镜像】切换阿里巴巴开源镜像站镜像——Debian镜像
- 获取android设备 id
- Android之——根据手势简单缩放图片
- Android编程实现连接Wifi(运用Wifi 相关 API)
- AirPods怎么连接Android设备 AirPods与安卓设备连接方法
- Android(安卓)通讯录详解contact2.db
- Android(安卓)无线调试
- Android(安卓)客户端与服务器交互方式
- 读懂Android(安卓)(1):使用Android内部的DownloadProvider下载文