> 文章列表 > Android11 wifi密码类型判断和总结

Android11 wifi密码类型判断和总结

Android11 wifi密码类型判断和总结

Android11 wifi密码类型判断和总结

本文主要介绍wifi密码类型的判断,这个对不同类型wifi连接分析有一定帮助。

文章目录

  • Android11 wifi密码类型判断和总结
    • 一、wifi 普通类型正常连接代码
    • 三、wifi获取基本信息获取
      • 1、获取wifi基本信息的api:
      • 2、梳理一下 WifiConfiguration 和 ScanResult :
      • 3、梳理一下wifi常用信息
    • 二、wifi密码加密类型判断
      • 1、ScanResult 中的判断和暴露的方法
      • 2、WifiConfiguration 中的判断
      • 3、SettingLib 中 AccessionPoint 中的判断
      • 4、ScanResultUtil 中的判断
      • 5、总结一下 ScanResult 、 WifiConfiguration 、 AccessionPoint 这三个类对象的联系和区别
        • (1) 各自特点和联系
        • (2)区别
    • 三、自定义wifi连接网络对加密类型封装
      • 1、思路
      • 2、WifiBean
        • (1)WifiBean对象的定义
      • 3、WifiUtils
    • 四、关于其他wifi加密类型相关知识
      • 1、Android 所有加密类型详解
      • 2、如果有同名的wifi 如何处理?
      • 3、 wifi 的 networkId
      • 4、wifi、热点信息保存文件位置:
      • 4、wifi 设置密码类型的不同合成 WifiConfiguration 写法
      • 5、wifi 已保存/已连接的情况修改数据
      • 6、wifi 加密类型判断错误会导致连接失败
    • 五、Android 加密类型使用总结
      • 1、Android wifi 的连接都是必现要基于WifiConfiguration对象
      • 2、wifi 扫描到的对象是 ScanResult ,已保存的wifi 对象是 WifiConfiguration
      • 3、WiFi常用的数据基本都在 ScanResult 中,都是要经过一定的转换才能得到
      • 4、wifi的开发要总结一个自己的封装类
      • 5、wifi 加密类型的判断主要是针对不同类型设置不同参数合成 WifiConfiguration

一、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) { //加密类型为:wepconfig.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) { //wpa3config.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/wpa2public 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");}//旧类型:weppublic 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");}//比较新的加密类型:wpa3public 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提到的所有类型都判断一次,最后再判断为NONEreturn "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 profilerequirePmf = 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_PSKpublic 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 lastprivate 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); //wpa3case 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*/@UnsupportedAppUsagepublic 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 , 加密类型 capabilitiespublic ScanResult mScanResult;//包含:是否代理和静态ippublic 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/wap2public static final String CAPABILITIES_EAP = "EAP";public static final String CAPABILITIES_SAE = "SAE"; //wpa3public static final String CAPABILITIES_EAP_B = "SUITE-B";public static final String CAPABILITIES_WAPI = "WAPI";public static final String CAPABILITIES_OWE = "OWE";//获取wifi 密码类型数值,参数为:ScanResult.capabilitiespublic 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.frequencypublic 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 wepwifiConfiguration.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/wap2wifiConfiguration.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.javawifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);break;case SECURITY_TYPE_SAE: //4 wap3wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); //4if (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/50663790SECURITY_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/123888636SECURITY_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/113921261SECURITY_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,如果设置密码字符串,也是会导致无法连接。

五、Android 加密类型使用总结

1、Android wifi 的连接都是必现要基于WifiConfiguration对象

2、wifi 扫描到的对象是 ScanResult ,已保存的wifi 对象是 WifiConfiguration

3、WiFi常用的数据基本都在 ScanResult 中,都是要经过一定的转换才能得到

4、wifi的开发要总结一个自己的封装类

5、wifi 加密类型的判断主要是针对不同类型设置不同参数合成 WifiConfiguration