Android11 wifi密码类型判断和总结
本文主要介绍wifi密码类型的判断,这个对不同类型wifi连接分析有一定帮助。
文章目录
一、wifi 普通类型正常连接代码
//wifi连接代码
public static void connect(Context context, WifiConfiguration config) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
//第一个参数是wifi配置信息,包含:WiFi 名称,wifi 加密类型,wifi 密码等基本信息
//第二个参数是连接回调,只有加密类型不匹配会报这个错误,密码错误或者其他异常情况这个回调是没用的
wifiManager.connect(config, null);
}
//创建wifi连接的基本信息
public WifiConfiguration createWifiInfo(String SSID, String Password, int TYPE) {
//创建配置信息对象
WifiConfiguration config = new WifiConfiguration();
//名称必须要加双引号
config.SSID = "\"" + SSID + "\"";
//密码类型设置和密码设置
if (TYPE == 0) { //无密码的情况
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
}
if (TYPE == 1) { //加密类型为:wep
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP);
//密码设置
if ((length == 10 || length == 26 || length == 58)
&& password.matches("[0-9A-Fa-f]*")) {
mBean.mConfig.wepKeys[0] = password;
} else {
mBean.mConfig.wepKeys[0] = '"' + password + '"';
}
}
if (TYPE == 2) { //加密类型为:wpa/wap2,目前最常用,普通wifi和手机热点,也有特殊手机比如红米可以发出wap3热点
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
if (password.matches("[0-9A-Fa-f]{64}")) {
config.preSharedKey = password;
} else {
config.preSharedKey = '"' + password + '"';
}
}
if (TYPE == 4) { //wpa3
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
if (mPasswordView.length() != 0) {
String password = mPasswordView.getText().toString();
config.preSharedKey = '"' + password + '"';
}
}
return config;
}
//普通Activity界面连接wifi网络代码
private connectWifi() {
//连接名称myHost,密码为12345678 的热点网络
connect(this, createWifiInfo("myHost", "12345678", 2))
}
从上面wifi连接的代码看,主要的逻辑都是在判断wifi密码类型上,所以wifi密码类型是很关键的。
无论是自己手动添加连接的wifi,还是点击扫描到的wifi,其实都是需要最后合成 WifiConfiguration 进行连接。
系统应用一直是以config进行连接的,普通应用很多先通过config获取networkId,再通过networkId,进行连接,
如果处理不当,一个同一个wifi 会有多个networkId,比如多次连接异常,但是未进行移除networkId就会有这个问题。
三、wifi获取基本信息获取
手动添加的情况,是我们比较了解该wifi加密类型的情况,直接输入对应参数进行连接就可以了。
如果是隐藏的wifi,也只能手动进行连接了!
下面主要介绍能扫描到的wifi列表获取。
1、获取wifi基本信息的api:
// 扫描出的wifi列表
private List<ScanResult> mWifiList = mWifiManager.getScanResults();
// 设备保存的wifi列表
private List<WifiConfiguration> mWifiConfigurations = mWifiManager.getConfiguredNetworks();
设备最开始的时候每个wifi条目都是一个 ScanResult 对象,
连接的时候我们创建了 WifiConfiguration ,并且把一下配置信息加进去,就成为我们后面连接wifi的配置对象。
2、梳理一下 WifiConfiguration 和 ScanResult :
WifiConfiguration 对象 = ScanResult 部分信息(名称) + 我们添加的信息(密码和加密类型)
WifiConfiguration 都是我们曾经连接过的信息,不管成功失败都有可能被保存,
但是应用中基本是进行了remove/forget操作,有些原生应用也没做,新手机上基本是判断未连接成功进行移除的!
3、梳理一下wifi常用信息
wifi 的基本信息开发者基本用下面这些就可以了:
1、名称
2、是否加密:
3、信号强度
4、是否5G信号
5、代理和静态ip设置
6、密码类型和密码
7、连接状态
ScanResult 包含:名称SSID , 信号强度 level 需要转换成 0-5, 是否5G信号 frequency 范围是否在 4900-5900 , 加密类型 capabilities 需要转换。
WifiConfiguration 包含:wifi名称,wifi加密类型,wifi密码 ,是否代理和静态ip ,不包含信号强度和是否5G信号信息
连接状态需要用 WifiManager 进行判断,判断是连接状态,还是断开状态!
WifiInfo 判断当前连接的wifi 信息。
需要注意的是,wifi信号强度和是否5G都是通过一定的转换才能得到结果。
网上找一大堆例子,其实都是根据源码修改过来的,但是就是源码api就是没暴露!
还有就是,WifiConfiguration 不包含信号强度和是否5G信号信息,这个也让很多人懵逼,所以要自己再遍历判断一次。
WifiConfiguration 里面有 preSharedKey 对象,但是你获取保存的wifi列表信息中打印这个数据,会发现为空。
所以wifi 密码并未对外暴露。真要获取,可以通过一个配置文件获取到密码,需要系统权限。
Android 11及更新版本 wifi信息保存的位置(热点信息也在同级目录下):
date/misc/apexdata/com.android.wifi/WifiConfigStore.xml
Androi 10或旧版本自己去百度一下哈,也可以看看我之前从源码分析wifi、热点信息保存文件位置的思路:
https://blog.csdn.net/wenzhi20102321/article/details/128593458
下面是本文的主要内容,wifi 密码类型的判断,在源码中多个地方是可以找到的,但是就是没用暴露!!!
并且网上针对这个东西的分析比较少!
二、wifi密码加密类型判断
先看看系统源码时如何判断的.
1、ScanResult 中的判断和暴露的方法
/**
* Describes the authentication, key management, and encryption schemes
//上面的翻译:描述身份验证、密钥管理和加密方案
* supported by the access point.
*/
public String capabilities;
//目前最常用类型:wpa/wpa2
public static boolean isScanResultForPskNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("PSK");
}
public static boolean isScanResultForWapiPskNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("WAPI-PSK");
}
public static boolean isScanResultForWapiCertNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("WAPI-CERT");
}
//企业级加密:EAP,有叫802.1 EAP,选项比较多,可能要证书
public static boolean isScanResultForEapNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("EAP");
}
public static boolean isScanResultForEapSuiteBNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("SUITE-B-192");
}
//旧类型:wep
public static boolean isScanResultForWepNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("WEP");
}
public static boolean isScanResultForOweNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("OWE");
}
public static boolean isScanResultForOweTransitionNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("OWE_TRANSITION");
}
//比较新的加密类型:wpa3
public static boolean isScanResultForSaeNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("SAE");
}
//既包含WPA2,也包含WPA3的情况
public static boolean isScanResultForPskSaeTransitionNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("PSK") && scanResult.capabilities.contains("SAE");
}
所以 加密类型还得看 ScanResult.capabilities字符包含哪些协议的字段。
这里可以看到 ScanResult 是包含了一下判断wifi 加密类型的静态方法。
其实常用的加密类型就上面有说明的几种,wpa/wap2/wap3,EAP,WEP(基本废弃),不然就是无密码NONE
虽然没有直接getType的接口,但是根据上面暴露的方法也能得到加密类型。
简单写法:
public static String getSecurityType(ScanResult scanResult) {
if (ScanResult.isScanResultForSaeNetwork(scanResult)) {
return "WPA3"
} else if (ScanResult.isScanResultForPskNetwork(scanResult)) {
return "WPA/WPA2"
} else if (ScanResult.isScanResultForWepNetwork(scanResult)) {
return "WEP"
} else if (ScanResult.isScanResultForEapNetwork(scanResult)) {
return "802.1 EAP"
} else { //最稳妥的还是,把ScanResult提到的所有类型都判断一次,最后再判断为NONE
return "NONE"
}
}
上面这个封装方法只能做参考,毕竟没有判断全部类型,但是对应目前Android应用上常用判断显示是没啥问题的。
看一段获取到的 ScanResult.capabilities 打印,输出了SSID 和 capabilities 的信息:
03-29 09:38:02.479 30989 30989 I getSecurity - noval 6 , capabilities = [WPA2-PSK-CCMP][RSN-PSK-CCMP][ESS] // 普通手机的热点wifi,wpa2
03-29 09:38:02.479 30989 30989 I getSecurity - KTC-SYRJB , capabilities = [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][RSN-PSK-CCMP+TKIP][ESS] //路由器wifi,wap2
03-29 09:38:02.479 30989 30989 I getSecurity - VPN , capabilities = [WPA-PSK-CCMP][WPA2-PSK-CCMP][RSN-PSK-CCMP][ESS] //路由器wifi,wap2
03-29 09:38:02.480 30989 30989 I getSecurity - lwz , capabilities = [ESS] //路由器无密码的wifi,NONE
03-29 09:38:02.480 30989 30989 I getSecurity - VPN_5G , capabilities = [WPA-PSK-CCMP][WPA2-PSK-CCMP][RSN-PSK-CCMP][ESS]
03-29 09:38:02.481 30989 30989 I getSecurity - tts , capabilities = [WPA-PSK-TKIP+CCMP][WPA2-PSK-TKIP+CCMP][RSN-PSK-TKIP+CCMP][ESS][WPS]
03-29 09:38:02.484 30989 30989 I getSecurity - Horion_fz , capabilities = [ESS]
03-29 09:38:02.484 30989 30989 I getSecurity - KTC-SYRJB5 , capabilities = [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][RSN-PSK-CCMP+TKIP][ESS]
03-29 09:38:02.485 30989 30989 I getSecurity - 爱连不连 , capabilities = [WPA2-PSK-CCMP][RSN-PSK-CCMP][ESS]
这里可以看到加密类型是有多个协议的,所以判断wifi加密类型判断协议里面包含的字段就可以。
可以看到这里的wifi基本都是支持WPA2 的,如果没有就看是否支持WPA,再没有就看是否支持 WEP 。。。最后就是NONE。
一般是先判断高级的,再网低级的判断,WPA3(SAE) 》WPA2 》WPA,显示高级的即可。具体的判断顺序可以参考 WifiConfiguration 对类型的判断。
最后应用进行连接还有设置wifi类型,这是Int类型的type,需要查看 WifiConfiguration 中的定义了!
2、WifiConfiguration 中的判断
WifiConfiguration.java 搜索加密类型关键字:“Security type”
//下面8个加密类型就是Android中支持的加密类型,也是wifi连接需要配置的类型值
/** Security type for an open network. */
public static final int SECURITY_TYPE_OPEN = 0;
/** Security type for a WEP network. */
public static final int SECURITY_TYPE_WEP = 1;
/** Security type for a PSK network. */
public static final int SECURITY_TYPE_PSK = 2;
/** Security type for an EAP network. */
public static final int SECURITY_TYPE_EAP = 3;
/** Security type for an SAE network. */
public static final int SECURITY_TYPE_SAE = 4;
/** Security type for an EAP Suite B network. */
public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
/** Security type for an OWE network. */
public static final int SECURITY_TYPE_OWE = 6;
/** Security type for a WAPI PSK network. */
public static final int SECURITY_TYPE_WAPI_PSK = 7;
/** Security type for a WAPI Certificate network. */
public static final int SECURITY_TYPE_WAPI_CERT = 8;
//这里可以看到一共有9大类的加密类型!
//WifiConfiguration 对应类型数据的设置,
//系统应用中也有对 allowedKeyManagement 属性进行配置的,
//其实就是和使用 setSecurityParams 方法进行配置一样,并且 setSecurityParams 更简单。
public void setSecurityParams(@SecurityType int securityType) {
// Clear all the bitsets.
allowedKeyManagement.clear();
allowedProtocols.clear();
allowedAuthAlgorithms.clear();
allowedPairwiseCiphers.clear();
allowedGroupCiphers.clear();
allowedGroupManagementCiphers.clear();
allowedSuiteBCiphers.clear();
switch (securityType) {
case SECURITY_TYPE_OPEN:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
break;
case SECURITY_TYPE_WEP:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
break;
case SECURITY_TYPE_PSK:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
break;
case SECURITY_TYPE_EAP:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
break;
case SECURITY_TYPE_SAE:
allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
requirePmf = true;
break;
case SECURITY_TYPE_EAP_SUITE_B:
allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
// Note: allowedSuiteBCiphers bitset will be set by the service once the
// certificates are attached to this profile
requirePmf = true;
break;
case SECURITY_TYPE_OWE:
allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
requirePmf = true;
break;
case SECURITY_TYPE_WAPI_PSK:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_PSK);
allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
break;
case SECURITY_TYPE_WAPI_CERT:
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_CERT);
allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
break;
default:
throw new IllegalArgumentException("unknown security type " + securityType);
}
}
// 通过 WifiConfiguration 对象获取加密类型 Type 的int值,
//值得注意的是,这个方法是私有的哦,可以自己写一个工具类,把它复制进去使用就可以
/**
* Fetch network type from network configuration.
*/
private static @WifiConfiguration.SecurityType int getNetworkType(WifiConfiguration config) {
if (WifiConfigurationUtil.isConfigForSaeNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_SAE;
} else if (WifiConfigurationUtil.isConfigForPskNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_PSK;
} else if (WifiConfigurationUtil.isConfigForWapiPskNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
} else if (WifiConfigurationUtil.isConfigForWapiCertNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
} else if (WifiConfigurationUtil.isConfigForEapNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_EAP;
} else if (WifiConfigurationUtil.isConfigForEapSuiteBNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
} else if (WifiConfigurationUtil.isConfigForWepNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_WEP;
} else if (WifiConfigurationUtil.isConfigForOweNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_OWE;
} else if (WifiConfigurationUtil.isConfigForOpenNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_OPEN;
}
throw new IllegalArgumentException("Invalid WifiConfiguration: " + config);
}
// 通过 ScanResult 对象获取加密类型 Type 的int值,
//值得注意的是,这个方法是私有的哦,可以自己写一个工具类,把它复制进去使用就可以
/**
* Fetch network type from scan result.
*/
private static @WifiConfiguration.SecurityType int getNetworkType(ScanResult scanResult) {
if (ScanResultUtil.isScanResultForSaeNetwork(scanResult)) {
return WifiConfiguration.SECURITY_TYPE_SAE;
} else if (ScanResultUtil.isScanResultForWapiPskNetwork(scanResult)) {
return WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
} else if (ScanResultUtil.isScanResultForWapiCertNetwork(scanResult)) {
return WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
} else if (ScanResultUtil.isScanResultForPskNetwork(scanResult)) {
return WifiConfiguration.SECURITY_TYPE_PSK;
} else if (ScanResultUtil.isScanResultForEapSuiteBNetwork(scanResult)) {
return WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
} else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) {
return WifiConfiguration.SECURITY_TYPE_EAP;
} else if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
return WifiConfiguration.SECURITY_TYPE_WEP;
} else if (ScanResultUtil.isScanResultForOweNetwork(scanResult)) {
return WifiConfiguration.SECURITY_TYPE_OWE;
} else if (ScanResultUtil.isScanResultForOpenNetwork(scanResult)) {
return WifiConfiguration.SECURITY_TYPE_OPEN;
} else {
throw new IllegalArgumentException("Invalid ScanResult: " + scanResult);
}
}
//还有个 getSsidAndSecurityTypeString 方法,但是是hide的,同样在应用中无法使用!
// allowedKeyManagement 属性是public 的,所以也是可以参考该方法对wifi类型加密显示的String
/** @hide
* return the SSID + security type in String format.
*/
public String getSsidAndSecurityTypeString() {
String key;
if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
} else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
|| allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
} else if (wepTxKeyIndex >= 0 && wepTxKeyIndex < wepKeys.length
&& wepKeys[wepTxKeyIndex] != null) {
key = SSID + "WEP";
} else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
key = SSID + KeyMgmt.strings[KeyMgmt.OWE];
} else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
key = SSID + KeyMgmt.strings[KeyMgmt.SAE];
} else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192];
} else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
key = SSID + KeyMgmt.strings[KeyMgmt.WAPI_PSK];
} else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
key = SSID + KeyMgmt.strings[KeyMgmt.WAPI_CERT];
} else if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
key = SSID + KeyMgmt.strings[KeyMgmt.OSEN];
} else {
key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
}
return key;
}
//这个方法是暴露的,可以访问,基本是返回key的值,比如wpa2的wifi名称:WiFiName,返回的字符串是(注意是有引号的): "WifiName"WPA_PSK
public String getKey() {
// Passpoint ephemeral networks have their unique identifier set. Return it as is to be
// able to match internally.
if (mPasspointUniqueId != null) {
return mPasspointUniqueId;
}
String key = getSsidAndSecurityTypeString();
if (!shared) {
key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
}
return key;
}
public BitSet allowedProtocols;
//为啥上面的 allowedKeyManagement 对象是会有数据,
//其实就是 WifiConfiguration 创建的是会调用了 setSecurityParams方法!
其实 WifiConfiguration 里面定义了内部类 KeyMgmt 里面细分了wifi加密类型的字符串和类型值。实际用处不大。
通过上面的代码可以看到,即使是已保存的wifi列表,并没有直接暴露的加密类型Type的接口,
不过看了源码后,封装一个getType和getTypeString 还是很简单的,下面是一个示例:
//获取Type 的int值,直接拿源码部分过来就可以
public static int getNetworkType(WifiConfiguration config) {
if (WifiConfigurationUtil.isConfigForSaeNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_SAE;
} else if (WifiConfigurationUtil.isConfigForPskNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_PSK;
} else if (WifiConfigurationUtil.isConfigForWapiPskNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
} else if (WifiConfigurationUtil.isConfigForWapiCertNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
} else if (WifiConfigurationUtil.isConfigForEapNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_EAP;
} else if (WifiConfigurationUtil.isConfigForEapSuiteBNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
} else if (WifiConfigurationUtil.isConfigForWepNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_WEP;
} else if (WifiConfigurationUtil.isConfigForOweNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_OWE;
} else if (WifiConfigurationUtil.isConfigForOpenNetwork(config)) {
return WifiConfiguration.SECURITY_TYPE_OPEN;
}
throw new IllegalArgumentException("Invalid WifiConfiguration: " + config);
}
//获取Type 的String 值,从源码 getSsidAndSecurityTypeString 方法去除SSID 即可。
public String getSecurityTypeString(WifiConfiguration config)) {
String key;
allowedKeyManagement = config.allowedKeyManagement;
if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
key = KeyMgmt.strings[KeyMgmt.WPA_PSK];
} else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
|| allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
key = KeyMgmt.strings[KeyMgmt.WPA_EAP];
} else if (wepTxKeyIndex >= 0 && wepTxKeyIndex < wepKeys.length
&& wepKeys[wepTxKeyIndex] != null) {
key = "WEP";
} else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
key = KeyMgmt.strings[KeyMgmt.OWE];
} else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
key = KeyMgmt.strings[KeyMgmt.SAE];
} else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
key = KeyMgmt.strings[KeyMgmt.SUITE_B_192];
} else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
key = KeyMgmt.strings[KeyMgmt.WAPI_PSK];
} else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
key = KeyMgmt.strings[KeyMgmt.WAPI_CERT];
} else if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
key = KeyMgmt.strings[KeyMgmt.OSEN];
} else {
key = KeyMgmt.strings[KeyMgmt.NONE];
}
return key;
}
上面没有做Type int <–> String 直接的转换,如果要可以自己做一个!
3、SettingLib 中 AccessionPoint 中的判断
看过原生Settings Wifi连接部分的代理就会值得,里面的Wifi条目用的是 AccessionPoint 对象进行数据判断。
AccessionPoint 对象是 WifiConfiguration 对象的进一步封装而成。
自己写的应用的封装其实可以参考 AccessionPoint ,更加实用简单。
//这里可以看到只定义了7大类的加密类型,其他的加密类型在实际应用中基本用不到!
public static final int SECURITY_NONE = 0;
public static final int SECURITY_WEP = 1;
public static final int SECURITY_PSK = 2;
public static final int SECURITY_EAP = 3;
public static final int SECURITY_OWE = 4; //值得注意的是,4和5没和 WifiConfiguration的加密类型值对应上,不要用错了!
public static final int SECURITY_SAE = 5;
public static final int SECURITY_EAP_SUITE_B = 6;
public static final int SECURITY_MAX_VAL = 7; // Has to be the last
private String ssid; //wifi名称
private int security; //加密类型int值
//这里可以看到 AccessionPoint 内部是包含 WifiConfiguration 对象的!
public WifiConfiguration getConfig() {
return mConfig;
}
public String getSsidStr() {
return this.ssid;
}
//获取加密类型值
public int getSecurity() {
return this.security;
}
//获取wifi 加密类型,参数:是否是简写名称,一般用true即可
public String getSecurityString(boolean var1) {
Context var2 = this.mContext;
if (!this.isPasspoint() && !this.isPasspointConfig()) {
if (this.mIsPskSaeTransitionMode) {
return var1 ? var2.getString(string.wifi_security_short_psk_sae) : var2.getString(string.wifi_security_psk_sae);
} else if (this.mIsOweTransitionMode) {
return var1 ? var2.getString(string.wifi_security_short_none_owe) : var2.getString(string.wifi_security_none_owe);
} else {
switch(this.security) { //判断七大类
case 0:
default:
return var1 ? "" : var2.getString(string.wifi_security_none);
case 1:
return var1 ? var2.getString(string.wifi_security_short_wep) : var2.getString(string.wifi_security_wep);
case 2:
switch(this.pskType) {
case 0:
default:
return var1 ? var2.getString(string.wifi_security_short_psk_generic) : var2.getString(string.wifi_security_psk_generic);
case 1:
return var1 ? var2.getString(string.wifi_security_short_wpa) : var2.getString(string.wifi_security_wpa);
case 2:
return var1 ? var2.getString(string.wifi_security_short_wpa2) : var2.getString(string.wifi_security_wpa2);
case 3:
return var1 ? var2.getString(string.wifi_security_short_wpa_wpa2) : var2.getString(string.wifi_security_wpa_wpa2);
}
case 3:
switch(this.mEapType) {
case 0:
default:
return var1 ? var2.getString(string.wifi_security_short_eap) : var2.getString(string.wifi_security_eap);
case 1:
return var1 ? var2.getString(string.wifi_security_short_eap_wpa) : var2.getString(string.wifi_security_eap_wpa);
case 2:
return var1 ? var2.getString(string.wifi_security_short_eap_wpa2_wpa3) : var2.getString(string.wifi_security_eap_wpa2_wpa3);
}
case 4:
return var1 ? var2.getString(string.wifi_security_short_owe) : var2.getString(string.wifi_security_owe);
case 5:
return var1 ? var2.getString(string.wifi_security_short_sae) : var2.getString(string.wifi_security_sae); //wpa3
case 6:
return var1 ? var2.getString(string.wifi_security_short_eap_suiteb) : var2.getString(string.wifi_security_eap_suiteb);
}
}
} else {
return var1 ? var2.getString(string.wifi_security_short_eap) : var2.getString(string.wifi_security_eap);
}
}
// 重点还是对security 类型的判断!下面进行分析:
//扫描的wifi列表
private final ArraySet<ScanResult> mScanResults = new ArraySet();
// AccessPoint 的构造方法,设置对象参数
AccessPoint(Context context, Collection<ScanResult> results) {
mContext = context;
setScanResults(results);
updateKey();
}
void setScanResults(Collection<ScanResult> var1) {
。。。
synchronized(this.mLock) {
this.mScanResults.clear();
this.mScanResults.addAll(var1);
}
}
private void updateBestRssiInfo() {
//遍历获取到对应的ScanResult ,进行数据设置等操作
this.security = getSecurity(this.mContext, var1);
}
//根据 ScanResult.capabilities 判断加密类型
private static int getSecurity(Context var0, ScanResult var1) {
boolean var2 = var1.capabilities.contains("WEP");
boolean var3 = var1.capabilities.contains("SAE");
boolean var4 = var1.capabilities.contains("PSK");
boolean var5 = var1.capabilities.contains("EAP_SUITE_B_192");
boolean var6 = var1.capabilities.contains("EAP");
boolean var7 = var1.capabilities.contains("OWE");
boolean var8 = var1.capabilities.contains("OWE_TRANSITION");
WifiManager var9;
if (var3 && var4) {
var9 = (WifiManager)var0.getSystemService("wifi");
return var9.isWpa3SaeSupported() ? 5 : 2;
} else if (var8) {
var9 = (WifiManager)var0.getSystemService("wifi");
return var9.isEnhancedOpenSupported() ? 4 : 0;
} else if (var2) {
return 1;
} else if (var3) {
return 5;
} else if (var4) {
return 2;
} else if (var5) {
return 6;
} else if (var6) {
return 3;
} else {
return var7 ? 4 : 0;
}
}
//信号强度获取,注意这里返回的值是0-4,是不需要转换的!
//这里可以看到是通过WifiManager 的接口转换的wifi信号强度
public int getLevel() {
return this.getWifiManager().calculateSignalLevel(this.mRssi);
}
从上面的代码看 AccessionPoint 的类型判断也是基于 ScanResult.capabilities 的字符串!
值得注意的是上面定义的类型值和 WifiConfiguration 对象的加密类型值未对应,
最终连接wifi 使用的是 WifiConfiguration 对象的配置!
4、ScanResultUtil 中的判断
ScanResultUtil.java 类是 framework 内部使用的一个工具类
frameworks\opt\net\wifi\service\java\com\android\server\wifi\util\ScanResultUtil.java
//根据 ScanResult 创建 WifiConfiguration对象
public static WifiConfiguration createNetworkFromScanResult(ScanResult scanResult) {
WifiConfiguration config = new WifiConfiguration();
config.SSID = createQuotedSSID(scanResult.SSID);
setAllowedKeyManagementFromScanResult(scanResult, config);
return config;
}
//给wifi名称添加引号
public static String createQuotedSSID(String ssid) {
return "\"" + ssid + "\"";
}
//给 WifiConfiguration 设置加密类型参数
public static void setAllowedKeyManagementFromScanResult(ScanResult scanResult,
WifiConfiguration config) {
if (isScanResultForSaeNetwork(scanResult)) {
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
} else if (isScanResultForWapiPskNetwork(scanResult)) {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_PSK);
} else if (isScanResultForWapiCertNetwork(scanResult)) {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_CERT);
} else if (isScanResultForPskNetwork(scanResult)) {
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
} else if (isScanResultForEapSuiteBNetwork(scanResult)) {
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
} else if (isScanResultForEapNetwork(scanResult)) {
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
} else if (isScanResultForWepNetwork(scanResult)) {
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP);
} else if (isScanResultForOweNetwork(scanResult)) {
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE);
} else {
config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
}
}
//判断加密类型。。。,ScanResult 也有一样的静态方法!
public static boolean isScanResultForPskNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("PSK");
}
public static boolean isScanResultForWapiPskNetwork(ScanResult scanResult) {
return scanResult.capabilities.contains("WAPI-PSK");
}
其实后面对象 WifiConfiguration/AccessionPoint 的加密类型都是基于扫描到的 ScanResult.capabilities 进行一定的封装转换得到的。
5、总结一下 ScanResult 、 WifiConfiguration 、 AccessionPoint 这三个类对象的联系和区别
(1) 各自特点和联系
ScanResult ,扫描到的wifi列表的单个 wifi 信息对象,普通应用中使用
WifiConfiguration , 已保存的单个 wifi 数据对象,提取了ScanResult 对象部分信息, 普通应用中使用
AccessionPoint ,提取了ScanResult 对象部分信息,比 WifiConfiguration 做了更多的封装(加了加密类型字符串和int值,wifi信号的获取等),
一般是系统应用使用,比如原生Settings。并且必要条件是导入SettingsLib这个系统Jar包。
Settings 应用中,扫描到的wifi 信息,已经封装到 AccessionPoint 对象。
可以看到 WifiConfiguration 和 AccessionPoint ,都是基于 ScanResult。
但是也有特殊情况,比如隐藏的wifi,是无法扫描到的,所以不经过 ScanResult。
隐藏的wifi连接,只要输入wifi名称,wifi加密类型参数 和 wifi 密码 即可。
那么问题来了,直接添加的wifi,即使连接成功也无法显示是否是 5G信号和wifi信号强度???
哈哈,如果是添加的网络,连接成功的话,是可以显示信号强度和是否5G的!通过 WifiInfo 这个对象即可获取到该信息。
WifiManager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
// 取得WifiInfo对象
WifiInfo mWifiInfo = mWifiManager.getConnectionInfo();
WifiInfo 的关键方法:
//获取WiFi名称,加了引号处理
public String getSSID() {
if (mWifiSsid != null) {
String unicode = mWifiSsid.toString();
if (!TextUtils.isEmpty(unicode)) {
return "\"" + unicode + "\"";
} else {
String hex = mWifiSsid.getHexString();
return (hex != null) ? hex : WifiManager.UNKNOWN_SSID;
}
}
return WifiManager.UNKNOWN_SSID;
}
//获取wifi信号,未经过处理的值,并非0-4的值
public int getRssi() {
return mRssi;
}
/**
* @hide
*/
public boolean is24GHz() {
return ScanResult.is24GHz(mFrequency);
}
/**
* @hide
*/
@UnsupportedAppUsage
public boolean is5GHz() {
return ScanResult.is5GHz(mFrequency);
}
//注意上面判断是否5G的方法是隐藏的,无法调用,下面的方法是暴露的!
//并且 ScanResult.is5GHz方法也是隐藏的,无法调用,不过看源码就能看出他判断过程
//通过获取到的 mFrequency 进行判断即可。
public int getFrequency() {
return mFrequency;
}
好像也没有太大信息,刚好补充了 WifiConfiguration 对象未包含信号强度和是否5G信号信息的缺陷!
(2)区别
区别,无非就是哪些信息不被包含。
ScanResult 包含:名称SSID , 信号强度 level 需要转换成 0-5, 是否5G信号 frequency 范围是否在 4900-5900 , 加密类型 capabilities 需要转换。
WifiConfiguration 包含:wifi名称,wifi加密类型,wifi密码(无法通过对象获取) ,是否代理和静态ip ProxyInfo ,不包含信号强度和是否5G信号信息
AccessionPoint 包含:WifiConfiguration对象,wifi名称,wifi加密类型,信号强度(如果已连接) ,不包含是否5G信号信息
连接状态需要用 WifiManager 进行判断Wifi状态,判断是连接状态,还是断开状态,连接中,断开中。。。!
WifiInfo 判断当前连接的wifi 信息 包含:名称,信号强度,是否5G。
总的来说,ScanResult 包含的信息是最多的,但是通过该对象无法判断是当前wifi是否是连接状态。
WifiConfiguration 多加了 代理对象和静态ip设置对象
AccessionPoint 包含了WifiConfiguration,并且增加获取wifi加密类型字符串,信号强度的方法
三、自定义wifi连接网络对加密类型封装
通过上面加密类型的代码,自己写一个加密类型的工具类应该是没啥问题了。
1、思路
如果自己写一个wifi demo,如果要每个wifi 都包含上面的全部关键信息,
那么可以自己定义一个Bean,定义所有关键信息变量,
还有一个懒的方法,WifiBean 里面包含两个对象:ScanResult 和 WifiConfiguration,那么就可以判断所有属性了;
如果未连接过的wifi ,WifiConfiguration 为空,已连接过的wifi WifiConfiguration对象是有数据的。
总的来说,以 ScanResult 列表为准,并且对应判断已保存的wifi (一般比较少),判断每一个wifi 名称(SSID)和设备地址(BSSID)。
2、WifiBean
(1)WifiBean对象的定义
public class WifiBean {
//包含:名称SSID , 信号强度 level 0-5, 是否5G信号 frequency 范围是否在 4900-5900 , 加密类型 capabilities
public ScanResult mScanResult;
//包含:是否代理和静态ip
public WifiConfiguration mWifiConfiguration;
//是否已连接,用于判断wifi列表顺序显示,已连接排第一(只有一个),已保存排第二(可能有多个),其他排后面
public int mState = 0;
}
3、WifiUtils
//获取wifi 密码类型数值,对标WifiConfiguration security types,需要自适配
/**
* Security type for an open network.
*/
public static final int SECURITY_TYPE_OPEN = 0;
/**
* Security type for a WEP network.
*/
public static final int SECURITY_TYPE_WEP = 1; //wep
/**
* Security type for a PSK network.
*/
public static final int SECURITY_TYPE_PSK = 2; //wpa/wpa2
/**
* Security type for an EAP network.
*/
public static final int SECURITY_TYPE_EAP = 3; //802.1x eap
/**
* Security type for an SAE network.
*/
public static final int SECURITY_TYPE_SAE = 4; //wap3
/**
* Security type for an EAP Suite B network.
*/
public static final int SECURITY_TYPE_EAP_SUITE_B = 5; //802.1x eap b
/**
* Security type for an OWE network.
*/
public static final int SECURITY_TYPE_OWE = 6; //后面的情况不判断了,这里就是other!
/**
* Security type for a WAPI PSK network.
*/
public static final int SECURITY_TYPE_WAPI_PSK = 7;
/**
* Security type for a WAPI Certificate network.
*/
public static final int SECURITY_TYPE_WAPI_CERT = 8;
//这里只适配0-5,加上第六种 Others,显示为OWE/WAPI,后面三种基本用不到!
//显示给用户的wifi 加密类型
public static final String NONE_STRING = "NONE";
public static final String WEP_STRING = "WEP";
public static final String PSK_STRING = "WPA/WPA2";
public static final String EAP_STRING = "802.1X/EAP";
public static final String SAE_STRING = "WPA3";
public static final String EAP_B_STRING = "802.1X/EAP_B";
public static final String OWE_WAPI = "OWE/WAPI"; //其他类型
//关键字(内部使用判断协议包含关系),可以依据ScanResult的静态判断协议方法:
public static final String CAPABILITIES_WEP = "WEP";
public static final String CAPABILITIES_PKS = "PSK"; //wpa/wap2
public static final String CAPABILITIES_EAP = "EAP";
public static final String CAPABILITIES_SAE = "SAE"; //wpa3
public static final String CAPABILITIES_EAP_B = "SUITE-B";
public static final String CAPABILITIES_WAPI = "WAPI";
public static final String CAPABILITIES_OWE = "OWE";
//获取wifi 密码类型数值,参数为:ScanResult.capabilities
public static int getWifiSecurityInt(String capabilities) { //扫描的ScanResult.capabilities
// 参考 WifiConfiguration getSsidAndSecurityTypeString() 并不完全
if (capabilities.contains(CAPABILITIES_SAE)) {
return SECURITY_TYPE_SAE;
} else if (capabilities.contains(CAPABILITIES_EAP_B)) {
return SECURITY_TYPE_EAP_SUITE_B;
} else if (capabilities.contains(CAPABILITIES_EAP)) {
return SECURITY_TYPE_EAP;
} else if (capabilities.contains(CAPABILITIES_PKS)) {
return SECURITY_TYPE_PSK;
} else if (capabilities.contains(CAPABILITIES_WEP)) {
return SECURITY_TYPE_WEP;
} else if (capabilities.contains(CAPABILITIES_WAPI) || capabilities.contains(CAPABILITIES_OWE)) { //其他类型判断
return SECURITY_TYPE_OWE;
}
//最后返回无密码情况
return SECURITY_TYPE_OPEN;
}
//获取wifi 密码类型字符,参数为:ScanResult.capabilities
//判断顺序参考:ScanResultUtil.setAllowedKeyManagementFromScanResult
// 先->后:WPA3->WAPI(常用的最后两种)-->PKS(WPA/WPA2)-->EAP_B-->EAP(802.1)-->WEP-->OWE(特殊的无密wifi)-->OPEN
//不过可以参考AccessPoint,不判断 WAPI 和 OWE ,因为基本不用用到。
public static String getWifiSecurityString(String capabilities) { //扫描的ScanResult.capabilities
// 参考 WifiConfiguration getSsidAndSecurityTypeString() 并不完全
if (capabilities.contains(CAPABILITIES_SAE)) {
return SAE_STRING;
} else if (capabilities.contains(CAPABILITIES_EAP_B)) {
return EAP_B_STRING;
} else if (capabilities.contains(CAPABILITIES_EAP)) {
return EAP_STRING;
} else if (capabilities.contains(CAPABILITIES_PKS)) {
return PSK_STRING;
} else if (capabilities.contains(CAPABILITIES_WEP)) {
return WEP_STRING;
} else if (capabilities.contains(CAPABILITIES_WAPI) || capabilities.contains(CAPABILITIES_OWE)) { //其他类型判断
return SAE_STRING;
}
return NONE_STRING; //最后返回无密码情况
}
//wifi 信号数值转换 -88,-77,-66,-55 --> 0-4 ,5格信号,参数为参数为:ScanResult.rssi
// frameworks\opt\net\wifi\service\java\com\android\server\wifi util\RssiUtil.java
//RssiUtil.calculateSignalLevel(mContext, rssi);
public static int calculateSignalLevel(int rssi) {
int[] thresholds = {-88, -77, -66, -55};
for (int level = 0; level < thresholds.length; level++) {
if (rssi < thresholds[level]) {
return level;
}
}
return thresholds.length;
}
public static final int BAND_5_GHZ_START_FREQ_MHZ = 5160;
public static final int BAND_5_GHZ_END_FREQ_MHZ = 5865;
//是否是5G信号,参数为 ScanResult.frequency
public static boolean is5GHz(int freqMhz) {
return freqMhz >= ScanResult.BAND_5_GHZ_START_FREQ_MHZ && freqMhz <= ScanResult.BAND_5_GHZ_END_FREQ_MHZ;
}
//根据加密类型值和密码,合成 WifiConfiguration 对象
@RequiresApi(api = Build.VERSION_CODES.R)
public static WifiConfiguration geWifiConfiguration(String wifiName, int securityType, String password) {
WifiConfiguration wifiConfiguration = new WifiConfiguration();
//名称配置
wifiConfiguration.SSID = convertToQuotedString(wifiName); //wifi 名称的必现加双引号
wifiConfiguration.hiddenSSID = true; //部分隐藏的wifi,如果不加该属性会不显示
//密码配置
switch (securityType) { //这个判断可以按0-6 的顺序
case SECURITY_TYPE_OPEN: // 0
//无密码的情况,一定不能设置密码字符串,否则会连接不上
wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
break;
case SECURITY_TYPE_WEP: //1 wep
wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP);
if (password.length() != 0) {
int length = password.length();
// WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
if ((length == 10 || length == 26 || length == 58)
&& password.matches("[0-9A-Fa-f]*")) {
wifiConfiguration.wepKeys[0] = password;
} else {
wifiConfiguration.wepKeys[0] = '"' + password + '"';
}
}
break;
case SECURITY_TYPE_PSK: //2 wpa/wap2
wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
if (password.length() != 0) {
if (password.matches("[0-9A-Fa-f]{64}")) {
wifiConfiguration.preSharedKey = password;
} else {
wifiConfiguration.preSharedKey = '"' + password + '"';
}
}
break;
case SECURITY_TYPE_EAP: //3 802.1 eap
//802.1X EAP,该项配置较多,不在这里配置
//需要具体了解可以参考代码:packages\apps\Settings\src\com\android\settings\wifi\WifiConfigController.java
wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
break;
case SECURITY_TYPE_SAE: //4 wap3
wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); //4
if (password.length() != 0) {
wifiConfiguration.preSharedKey = '"' + password + '"';
}
break;
case SECURITY_TYPE_EAP_SUITE_B: //5 802.1 eap_b
//802.1X EAP,该项配置较多,不在这里配置
wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
break;
case SECURITY_TYPE_OWE: //6 其他,不做判断
return null;
}
return wifiConfiguration;
}
上面只封装了几个方法:
getWifiSecurityInt 获取加密类型值
getWifiSecurityString 获取加密类型字符串
calculateSignalLevel 计算WiFi信号强度
is5GHz 判断当前wifi 是否是5G 网络
根据密码类型和具体参数封装 WifiConfiguration 对象。
这几个方法在Android 上是没有可以直接调用的api,只能自己封装。
根据实际需求,其实也还可以进行进一步封装常用方法:
比如
获取wifi 密码, 有点难,估计要系统权限,系统保存的配置文件中有密码字符串
获取wifi 代理情况,
获取wifi 静态ip 情况
判断wifi 是否保存状态 (根据wifi名称)
判断wifi 是否连接状态 (根据wifi名称)
值得注意的是上面虽然有封装了获取 WifiConfiguration 对象的静态方法,
但是配置对象有代理和静态ip 的情况,也需要把对应信息设置进去。
四、关于其他wifi加密类型相关知识
1、Android 所有加密类型详解
加密协议介绍:
SECURITY_TYPE_WEP = 1; //比较旧的加密方式,基本很少用,不太安全
更多文字介绍:https://blog.csdn.net/u013403237/article/details/50663790
SECURITY_TYPE_PSK = 2; //目前常用
包含WPA/WPA2
更多文字介绍:https://www.jianshu.com/p/9316c433ec5f/
SECURITY_TYPE_EAP = 3; //非常安全
EAP 的类型,是一种企业验证的安全类型,EAP 全称叫 802.1X/EAP 他常常给误解成 802.11x。
EAP 的意思就是可扩展认证协议的缩写。
最常部署的 EAP 验证类型包括 EAP-MD-5、EAP-TLS、EAP-LEAP、EAP-TTLS、EAP-Fast、EAP-PEAP;
所以EAP网络也是连接wifi参数最多的网络,还需要添加客户端和服务器端的证书安装。
更多文字介绍:https://blog.csdn.net/hl1293348082/article/details/123888636
SECURITY_TYPE_SAE = 4;
SAE最早是802.11s中为mesh网络提出的基于password的认证和key生成协议[1]。在WPA2-PSK中,PMK就是PSK,直接来源于密钥;
而SAE则保证任何STA pair(AP-STA,nonAP-STA)在不同的session都有不同的PMK,使用SAE认证的个人无线网络通常称为WPA3-PSK/WPA3-Personal。
简单的说SAE,就是WPA2的升级,简称WPA3
更多文字介绍:https://blog.csdn.net/qq_23087099/article/details/113921261
SECURITY_TYPE_EAP_SUITE_B = 5;
EAP网络的另一种加密形式,具体介绍查不出
SECURITY_TYPE_OWE = 6;
未查出相关介绍,在当前类中发现,入下介绍,Opportunististic (共产主义),大概是共享网络的一种加密格式吧。
/**
* Opportunististic Wireless Encryption
*/
public static final int OWE = 9;
最后两种:SECURITY_TYPE_WAPI_X
WAPI(无线网络WLANAuthenticationandPrivacyInfrastructure)是我国自主研发并大力推行的无线网络WLAN安全标准,
它通过了IEEE(注意,不是Wi-Fi)认证和授权,是一种认证和私密性保护协议,其作用类似于802.11b中的WEP,但是能提供更加完善的安全保护。
想要更多协议的了解可以看:
https://blog.csdn.net/wenzhi20102321
2、如果有同名的wifi 如何处理?
如果有同名的wifi ,如果连接其中一个后,怎么判断另外一个是否已连接?
其实每个wifi ScanResult 除了有名称ssid 外,还有 bssid ,这个是wifi 的一个固定地址,可以使用这个进行区分。
不过很多应用并没有做这个判断,如果确实遇到这样的问题,可以多判断 bssid 进行完善。
3、 wifi 的 networkId
每个连接过的wifi,都是会有一个 networkId,这个 networkId 从 0 开始递增。
这个 networkId 是保存在 WifiConfiguration 对象中的。
某个wifi 的忘记和重新连接都是可以通过这个 networkId 进行操作就可以了。
4、wifi、热点信息保存文件位置:
可以参考之前写的博客:
https://blog.csdn.net/wenzhi20102321/article/details/128593458
4、wifi 设置密码类型的不同合成 WifiConfiguration 写法
比如判断 PKS (WPA/WAP2)的WiFi 加密类型时:
//有的应用这样写:
wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
//有的应用这样写:
wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
第二种写法是Android11 之后才有的写法,其实具体实现也是往 wifiConfiguration.allowedKeyManagement 里面写入数据。
但是 有些密码类型需要写入多个数据,而第二种写法调用api就可以了,比较方便,准确。
5、wifi 已保存/已连接的情况修改数据
直接对 WifiConfiguration 对象进行修改即可,并且重新进行连接操作。
比如一般是修改代理或者静态ip 等数据,不需要修改的可以不用覆盖。
修改数据的情况,值得注意的是不要直接 new WifiConfiguration ,
而是用原来的 WifiConfiguration 再修改对应的数据可以,比如不修改密码的情况,不需要对密码参数进行设置。
6、wifi 加密类型判断错误会导致连接失败
wifi 连接类型判断错误,会导致wifi 无法连接。
但是也不是所有类型判断错误都会无法连接,
比如wpa3 类型的wifi 设置成 wpa/wpa2 ,亲测是可以正常连接的。
但是如果 wpa类型的网络,设置成 wpa3 类型,不知道能不能连接,没试!估计不能吧。
(最新的红米手机是可以发出wpa3 类型的热点的!)
还有无密码的wifi,如果设置密码字符串,也是会导致无法连接。