Android11 wifi密码类型判断和总结

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,如果设置密码字符串,也是会导致无法连接。

五、Android 加密类型使用总结

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

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

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

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

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

猜你喜欢

转载自blog.csdn.net/wenzhi20102321/article/details/130115842
今日推荐