记录:WiFi的链接

摘要:最近遇到需要自己把WiFi的界面重新定义一下。并进行可以连接。在这里进行记录一下,方便后面的查找

  对应WiFi的使用的想到的肯定是WifiManager,因为各种各样的 Manager提供简单方便的使用,在看见WifiManager的看是就基本上说明由那些作用。

It deals with several categories of items:


  • The list of configured networks. The list can be viewed and updated,
    and attributes of individual entries can be modified.
  • The currently active Wi-Fi network, if any. Connectivity can be
    established or torn down, and dynamic information about the state of
    the network can be queried.
  • Results of access point scans, containing enough information to
    make decisions about what access point to connect to.
  • It defines the names of various Intent actions that are broadcast upon any sort of change in Wi-Fi state.

  在类的开始有一句话很重要 `it should only be obtained from an application context, and not from any other derived context to avoid memory leaks within the calling process. hah,我也是通过必应翻译的,意思是我们要用 context.getApplicationContext(),而不是其子类,因为这样可能造成内存溢出。在后面的版本(N)中,这个问题系统自身就解决了。

  在实例化好WifiManager对象后,调用startScan( )方法就开始进行扫描,再调用getScanResults( )。就会返回搜索到的WiFi信息,返回一个List 。ScanResult类中,我用到的只有 SSID(热点的名称),capabilities(包含了密码为何种的加密方式),level(信号的强度)。

  这样就好了。答案却不是。在通过 WifiManager.isWifiEnabled()的方法判断wifi是否打开之后,用WifiManager.setWifiEnabled(true)或false,去开关wifi。关闭wifi重新打开之后返回的扫描结果长度为 0。为此不得不提到 WifiManager中的几个广播了。在这些广播中可以返回各种数据,有的广播可以返回几个数据,通过不key去获取。

WifiManager中几个用到的广播
广播(action) 作用 获取返回值的key 返回值
WIFI_STATE_CHANGED_ACTION = “android.net.wifi.WIFI_STATE_CHANGED” 指示已启用 wi-fi、禁用、启用、禁用或未知。
  1. EXTRA_WIFI_STATE
  2. EXTRA_PREVIOUS_WIFI_STATE
  1. getIntExtra(String,int),共五种状态
  2. 返回前一个wifi状态,不知道什么意思,没有测试过。不知道是不是像相机一个的前后,因为上面它写了这个要支持才行
SUPPLICANT_CONNECTION_CHANGE_ACTION = “android.net.wifi.supplicant.CONNECTION_CHANGE” 已经完全连接或者已经完全失去连接所触发的广播。因为我在打开WiFi,他自动连接的时候就调用了 EXTRA_SUPPLICANT_CONNECTED getBooleanExtra(String,boolean)。 为true, 表示当前已成功连接, 反之, 则是断开了连接。
NETWORK_STATE_CHANGED_ACTION wi-fi连接的状态已更改,以 NetworkInfo对象的形式返回,如果新的状态已连接,则额外的提供接入点BSSID和WifiInfo
  1. EXTRA_NETWORK_INFO
  2. EXTRA_BSSID
  3. EXTRA_WIFI_INFO
  1. getParcelableExtra(String),返回一个NetworkInfo
  2. getStringExtra(String), 一个字符串的查找键, 给出了我们所连接的接入点的 BSSID。仅在新状态连接时出现。
  3. getParcelableExtra(String),返回一个WifiInfo。对象的查找键, 提供有关连接的访问点的信息。仅在新状态连接时出现。
SUPPLICANT_STATE_CHANGED_ACTION = “android.net.wifi.supplicant.STATE_CHANGE” 明建立连接的状态访问点已更改,返回一个SupplicantState。请求状态是 wi-fi 特定的, 如果只是对连接的总体状态感兴趣, 则通常不是最有用的东西。在测试时候在SUPPLICANT_CONNECTION_CHANGE_ACTION之前调用。
  1. EXTRA_NEW_STATE
  2. EXTRA_SUPPLICANT_ERROR
  1. getParcelableExtra(String),描述新状态的 SupplicantState
  2. getIntExtra(String, int), SupplicantState 的查找键, 描述请求程序错误代码 (如果有)
SCAN_RESULTS_AVAILABLE_ACTION = “android.net.wifi.SCAN_RESULTS” 访问点扫描已完成, 并可从请求者那里获得结果。调用getScanResults ()以获取结果 EXTRA_RESULTS_UPDATED 指示扫描是否成功完成。 getScanResults()
RSSI_CHANGED_ACTION = “android.net.wifi.RSSI_CHANGED” 信号强度改变 getIntExtra(WifiManager.EXTRA_NEW_RSSI, 0)
NETWORK_IDS_CHANGED_ACTION = “android.net.wifi.NETWORK_IDS_CHANGED” 已配置网络的网络 id 可能已更改。

  可以通过WIFI_STATE_CHANGED_ACTION广播去获取当前wifi的状态,在状态为 WIFI_STATE_ENABLE情况下使用startScan( )方式,开启搜索。在SCAN_RESULTS_AVAILABLE_ACTION广播中去获取这个搜索的结果。使用NETWORK_STATE_CHANGED_ACTION去获取到这个wifi连接的一状态。其中wifi状态由五种分别是:WIFI_STATE_DISABLED ,WIFI_STATE_DISABLING ,WIFI_STATE_ENABLED ,WIFI_STATE_ENABLING ,WIFI_STATE_UNKNOWN。而NetworkInfo的状态通过getState()去得到NetworkInfo.State 。NetworkInfo.State.DISCONNECTED表示连接已断开。NetworkInfo.State.CONNECTED表示连接完成。通过wifiManager.getConnectionInfo()获得WifiInfo,再通过getSSID( )获取到对应的热点名称。其中,NetworkInfo.State还有几种其它状态。还可有更加具体状态信息,通过 NetworkInfo.DetailedState stateD = info.getDetailedState(),去获取,其中有很多状态,如:IDLE(空闲),SCANNING(正在扫描),CONNECTING(连接中),AUTHENTICATING(正在验证身份信息),OBTAINING_IPADDR(正在获取IP地址),CONNECTING(连接中),CONNECTED(已连接),等等,等等。一系列。而且后面的还在增加。如:VERIFYING_POOR_LINK(暂时关闭(网络状况不佳))需要API16,CAPTIVE_PORTAL_CHECK(判断是否需要浏览器二次登录)API17。

  以下是我关闭wifi和打开wifi,以上几个广播打印的 Log

//关闭wifi
I/WifiAdminUtil ->: BroadCastReceiver NETWORK_STATE_CHANGED_ACTION
 I/WifiAdminUtil ->: BroadCastReceiver NETWORK_STATE_CHANGED_ACTION
 I/WifiAdminUtil ->: BroadCastReceiver WIFI_STATE_CHANGED_ACTION 
                                                                        extra = 3
I/WifiAdminUtil ->: BroadCastReceiver SUPPLICANT_STATE_CHANGED_ACTION 
                                                                        err = 0
I/WifiAdminUtil ->: BroadCastReceiver SUPPLICANT_CONNECTION_CHANGE_ACTION 
                                                                        extra = false
I/WifiAdminUtil ->: BroadCastReceiver WIFI_STATE_CHANGED_ACTION 
                                                                        extra = 0

//开启wifi
I/WifiAdminUtil ->: start scan millis1503825827873
I/WifiAdminUtil ->: BroadCastReceiver WIFI_STATE_CHANGED_ACTION 
                                                                        extra = 1
I/WifiAdminUtil ->: BroadCastReceiver WIFI_STATE_CHANGED_ACTION 
                                                                        extra = 2
I/WifiAdminUtil ->: BroadCastReceiver SUPPLICANT_CONNECTION_CHANGE_ACTION 
                                                                        extra = true
I/WifiAdminUtil ->: BroadCastReceiver SUPPLICANT_STATE_CHANGED_ACTION 
                                                                        err = 0
I/WifiAdminUtil ->: BroadCastReceiver SCAN_RESULTS_AVAILABLE_ACTION
I/WifiAdminUtil ->: BroadCastReceiver SUPPLICANT_STATE_CHANGED_ACTION 
                                                                        err = 0
I/WifiAdminUtil ->: BroadCastReceiver SUPPLICANT_STATE_CHANGED_ACTION 
                                                                        err = 0
I/WifiAdminUtil ->: BroadCastReceiver SUPPLICANT_STATE_CHANGED_ACTION 
                                                                        err = 0
I/WifiAdminUtil ->: BroadCastReceiver NETWORK_STATE_CHANGED_ACTION
I/WifiAdminUtil ->: BroadCastReceiver SUPPLICANT_STATE_CHANGED_ACTION 
                                                                        err = 0
I/WifiAdminUtil ->: BroadCastReceiver RSSI_CHANGED_ACTION 
                                                                        extra = -38
I/WifiAdminUtil ->: BroadCastReceiver SUPPLICANT_STATE_CHANGED_ACTION 
I/WifiAdminUtil ->: BroadCastReceiver RSSI_CHANGED_ACTION 
                                                                        extra = -38
I/WifiAdminUtil ->: BroadCastReceiver NETWORK_STATE_CHANGED_ACTION
I/WifiAdminUtil ->: BroadCastReceiver NETWORK_STATE_CHANGED_ACTION
I/WifiAdminUtil ->: BroadCastReceiver NETWORK_STATE_CHANGED_ACTION



  从以上获取搜索的结果后,我们就可以进行连接。在连接之前先查看一下断开的连接的操作。不破不立吗,没有断开之前的连接。也就不能有新的连接了。断开通过mWifiManager.disconnect()就可以断开了。在手机还有一个忘记密码的操作,其忘记连接密码可以通过如下就实现:

  1. mWifiManager.getConnectionInfo()获取当前连接的WifiInfo
  2. mWifiInfo.getNetworkId()通过此方法获取网络的ID
  3. mWifiManager.disableNetwork(netId),关闭断当前的网络
  4. mWifiManager.disconnect()与当前活动的接入点解除关联

  ’好了,接下我们就可以通过WiFi的名称和密码。完成WiFi的连接。连接的主要就是通过搜索到的wifi名称,和该wifi的密码加密类型。加上输入的密码。怎么创建成一个符合要求的类对象(WifiConfiguration)。先说说密码的加密类型,如下:
 /**
     * 判断扫描的的热点的加密方式,通过 capabilities字段
     *
     * @param scanResult
     * @return
     */
    public String encryptionMetho(ScanResult scanResult) {
        //在demo和我自己在WifiConfiguration KeyMgmt 中看见的不一样
        /**
         * 在自己的测试中,如果没有密码的公共热点。capabilities = [ESS],其余都有各种加密方式在前面
         *
         * 其中源于百度的引用 https://zhidao.baidu.com/question/197383906.html
         * 密码的方式共有 3种,WEP , WPA , WPA2
         * WEP 的密码架构有缺陷,很容易让无线黑客攻击,不建议使用
         * WPA , WAP2 都是很强壮的密码,目前的破解难度很大(当然,原密码不能过于的简单)
         * 至于 AES , TKIP , TKIP&AES 这些都是 wap的加密算法
         */
        String desc = "";
        String descOri = scanResult.capabilities;
        if (!descOri.equals("")|| !TextUtils.isEmpty(descOri)|| descOri != null) {
            if (descOri.toUpperCase().contains("WPA-PSK")) {
                desc = "WPA";
            } else if (descOri.toUpperCase().contains("WPA2-PSK")) {
                desc = "WPA2";
            } else if (descOri.toUpperCase().contains("WPA-PSK") && descOri.toUpperCase().contains("WPA2-PSK")) {
                desc = "WPA/WPA2";
            } else if (descOri.toUpperCase().contains("WEP")) { //很少使用
                desc = "WEP";
            } else {
                desc = "";
            }
        }
        return desc ;
    }

  以上自是自己写的一个,写在上面只是想知道这个对不对。其中的创建对象的方法是直接从网络上拷贝的一个,看来一下基本上博客的创建方式是一样的。自己也是抄抄,测试一下可以使用。由于现在的加密方式基本是WPA ,WPA2。没有找到WEP。搜索到热点的 capabilities的字段内容为“[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS]“ ,估计其中创建判断PSK估计就是指WPA|WPA2的加密方式吧!其中WifiConfiguration中的几个变量的意思先介绍一下
WifiConfiguration几个变量名介绍
变量名 含义
SSID 热点的名称
preSharedKey 热点的密码
hiddenSSID 是否隐藏SSID
status 是否启用这用这个热点配置
allowedAuthAlgorithms IEEE 802.11认证算法 OPEN
allowedGroupCiphers 组秘钥TKIP+CCMP
allowedPairwiseCiphers 对称秘钥TKIP+CCMP
allowedKeyManagement 秘钥管理WPA_PSK
allowedProtocols 加密协议WPA+RSN

  其创建一个WifiConfiguration对象如下:
 /**
     * 创建一个 WifiConfiguration,其参数配置看 connect里面的注释
     *
     * @return
     */
    private WifiConfiguration createWifiInfo(String ssid, String psk, int type) {

        WifiConfiguration config = new WifiConfiguration();
        config.allowedAuthAlgorithms.clear();
        config.allowedGroupCiphers.clear();
        config.allowedKeyManagement.clear();
        config.allowedPairwiseCiphers.clear();
        config.allowedProtocols.clear();
        config.SSID = "\"" + ssid + "\"";

        //查看以前是否也配置过这个网络
        WifiConfiguration tempConfig = isExsits(ssid);
        if (tempConfig != null) { //以前配置过,就移除以前的
            mWifiManager.removeNetwork(tempConfig.networkId);
        }

        //三种加密方式,没有密码,wpa,wep
        if (type == TYPE_NO_PASSWD) {
//            config.wepKeys[0] = "";
//            config.wepTxKeyIndex = 0;
            //有的博客为以上两句编写的话,不可以连接上没有密码的热点(在模拟器测试是这样的,真机未测)
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
        } else if (type == TYPE_WEP) {

            config.preSharedKey = "\"" + psk + "\"";
            config.hiddenSSID = true;
            config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            config.wepTxKeyIndex = 0;

        } else if (type == TYPE_WPA) {

            //修改之后的配置
            config.preSharedKey = "\"" + psk + "\"";
            config.hiddenSSID = true;
            config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);

            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);

            config.status = WifiConfiguration.Status.ENABLED;

        } else {
            return null;
        }

        Log.i(TAG,"createWifiInfo "+"ssid = "+ssid+" , psk = "+psk+" ,type = "+type) ;
        return config;
    }
  其中注意在没有密码的创建要把注释的两局注释掉,不然真的不能成功。上面里面还有两个方法用于判断之前是否配置过,和删除配置(系统方法)。其代码如下:
    /**
     * 循环遍历查出以前是否调加过该网络
     *
     * @param ssid 热点名称
     * @return 如果添加过,则返回以前的配置
     */
    private WifiConfiguration isExsits(String ssid) {

        List networks = mWifiManager.getConfiguredNetworks();
        for (WifiConfiguration network : networks) {
            if (network.SSID.equals("\"" + ssid + "\"")) {
                return network;
            }
        }
        return null;
    }



  上面就准备好了一切,就可以开始连接了。步骤如下:

  1. mWifiManager.addNetwork(wifiConfig) ,添加一个新的网络描述为一组配置的网络。
  2. mWifiManager.disconnect() ,断开连接
  3. mWifiManager.enableNetwork(netId, true) ,设置为true,尝试其他的连接断开
  4. mWifiManager.reconnect()

  通过以上几个步级完成连接,在这里面我并没有调用“mWifiManager.saveConfiguration()“ 在连接只有,WiFi热点也被记录了下来。看里面没有写默认会被保存,可能是测试机的原因吧。
  代码连接: http://download.csdn.net/download/guyuelin123/9952893

参考链接

  1. Android Wifi模块 ScanResult类源码分析
  2. Android之WifiManager
  3. Android wifi的WifiInfo对象详解
  4. Android WiFi开发教程(二)——WiFi的搜索和连接
  5. Android应用程序创建热点以及自动链接Wifi,我遇到的问题以及我是怎么解决的
  6. Android连接指定Wifi的方法
  7. Android WIFI 分析(一)

你可能感兴趣的:(Android)