Android进阶之路 - WiFi的全面使用

1,528 阅读7分钟

起源:因在售货机上需要设置WiFi,但是跳转之后发现无返回操作(其实Android系统在跳转系统子界面时有返回的操作,只不过被隐藏了,如果你的需求是跳转WiFi需要返回上级界面的话,可以点击此处来完美解决你的问题),故此想着自己获取WiFi列表然后填充到RecyclerView中,之后在进行WiFi连接,最终总结了此篇回忆 ~

基础课堂

虽然我写了Demo实现了一些需求,但是这方面的基础确实一般,索性总结的同时进行了二次理解,在学基础的时候借鉴了一篇老的文章,虽然现在可能有些方法已经被更新,但是十之八九皆是相同 ~

6.0版本中如果未开启GPS是无法获取到扫描列表

需要动态申请ACCESS_COARSE_LOCATION权限

状态分类

Android官方文档中WiFi的五种状态

  • 网卡正在关闭
    WIFI_STATE_DISABLING WIFI ( 状态码:0 )
  • 网卡不可用
    WIFI_STATE_DISABLED WIFI ( 状态码:1 )
  • 网卡正在打开
    WIFI_STATE_ENABLING WIFI ( 状态码:2 )
  • 网卡可用
    WIFI_STATE_ENABLED WIFI ( 状态码:3 )
  • 网卡状态不可知
    WIFI_STATE_UNKNOWN WIFI ( 状态码:4 )

加密方式

加密方式场景配置
None开放网络,不加密无需密码
WEP旧的加密方式,不推荐使用仅需密码
WPA/WPA2最常见的加密方式仅需密码
EAP企业加密方式ID+密码验证

基础对象

想要获得wifi的信息,就须要一个WifiManager对象

 WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);

常用基类

ScanResult

通过wifi 硬件的扫描来获取一些周边的wifi 热点的信息,包含接入点名字、接入点信息的强弱、还有接入点使用的安全模式,是WPA、WEP,内部只提供了一个方法,就是将获得信息编程字符串toString();

字段含义
BSSID接入点的地址,这里主要是指小范围几个无线设备相连接所获取的地址,比如说两台笔记本通过无线网卡进行连接,双方的无线网卡分配的地址
SSID网络的名字,当我们搜索一个网络时,就是靠这个来区分每个不同的网络接入点
Capabilities网络接入的性能,这里主要是来判断网络的加密方式等
Frequency频率,每一个频道交互的MHz 数
Level等级,主要来判断网络连接的优先数。
wifiManager

管理WiFi连接,内部提供了一个内部的wifiManagerLock子类,主要作用在普通的状态下,假设我们的wifi 的状态处于闲置。那么网络的连通,将会临时中断;可是假设我们把当前的网络状态锁上,那么wifi 连通将会保持在一定状态。当然接触锁定之后,就会恢复常态 ~

方法含义
addNetwork(WifiConfiguration config)通过获取到的网络的链接状态信息,来加入网络
calculateSignalLevel(int rssi , int numLevels)计算信号的等级
compareSignalLevel(int rssiA, int rssiB)对照连接A 和连接B
createWifiLock(int lockType, String tag)创建一个wifi 锁,锁定当前的wifi 连接
disableNetwork(int netId)让一个网络连接失效
disconnect()断开连接
enableNetwork(int netId, Boolean disableOthers)连接一个连接
getConfiguredNetworks()获取网络连接的状态
getConnectionInfo()获取当前连接的信息
getDhcpInfo()获取DHCP 的信息
getScanResulats()获取扫描測试的结果
getWifiState()获取一个wifi 接入点是否有效
isWifiEnabled()推断一个wifi 连接是否有效
pingSupplicant()ping 一个连接。推断能否连通
ressociate()即便连接没有准备好,也要连通
reconnect()假设连接准备好了,连通
removeNetwork()移除某一个网络
saveConfiguration()保留一个配置信息
setWifiEnabled()让一个连接有效
startScan()開始扫描
updateNetwork(WifiConfiguration config)更新一个网络连接的信息
WifiInfo

WiFi连接成功之后,可通过WifiInfo类获取一些WiFi的具体信息

方法含义
getBSSID()获取BSSID
getDetailedStateOf()获取client的连通性
getHiddenSSID()获得SSID 是否被隐藏
getIpAddress()获取IP 地址
getLinkSpeed()获得连接的速度
getMacAddress()获得Mac 地址
getRssi()获得802.11n 网络的信号
getSSID()获得SSID
getSupplicanState() 返回详细client状态的信息
wifiConfiguration

连通一个wifi 接入点的时候,需要获取到的一些信息 ~

类名含义
WifiConfiguration.AuthAlgorthm用来判断加密方法
WifiConfiguration.GroupCipher获取使用GroupCipher 的方法来进行加密
WifiConfiguration.KeyMgmt获取使用KeyMgmt 进行
WifiConfiguration.PairwiseCipher获取使用WPA 方式的加密
WifiConfiguration.Protocol获取使用哪一种协议进行加密
wifiConfiguration.Status获取当前网络的状态

简单方法

此下方法较老,未必全部可用,只是当作笔记

获取WifiManager

 WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);

开启WiFi

public void openWifi(){
	if(!wifiManager.isWifiEnabled()){
		wifiManager.setWifiEnabled(true);
	}
}

关闭WiFi

private void closeWifi() {
	if (wifiManager.isWifiEnabled()) {
		wifiManager.setWifiEnabled(false);
	}
}

扫描WiFi信号

public void WifiStartScan(){
	wifiManager.startScan();
}

得到扫描WiFi结果

public List<ScanResult> getScanResults(){
	//得到扫描结果
	return wifiManager.getScanResults();
}

连接指定Id的WiFi

//连接指定Id的WIFI
public boolean ConnectWifi(int wifiId){
	for(int i = 0; i < wifiConfigList.size(); i++){
		WifiConfiguration wifi = wifiConfigList.get(i);
		if(wifi.networkId == wifiId){
			while(!(localWifiManager.enableNetwork(wifiId, true))){//激活该Id,建立连接
			    //status:0--已经连接,1--不可连接,2--可以连接
				Log.i("ConnectWifi",String.valueOf(wifiConfigList.get(wifiId).status));
			}
			return true;
		}
	}
	return false;
}

得到WiFi的配置好的信息,包含配置好的密码

public void getConfiguration(){
	wifiConfigList = localWifiManager.getConfiguredNetworks();//得到配置好的网络信息
	for(int i =0;i<wifiConfigList.size();i++){
		Log.i("getConfiguration",wifiConfigList.get(i).SSID);
		Log.i("getConfiguration",String.valueOf(wifiConfigList.get(i).networkId));
	}
}

根据WiFi的名称SSID判定指定WiFi是否已经配置好,配置好则返回其networkId,用于连接 ~

public int IsConfiguration(String SSID){
	Log.i("IsConfiguration",String.valueOf(wifiConfigList.size()));
	for(int i = 0; i < wifiConfigList.size(); i++){
		Log.i(wifiConfigList.get(i).SSID,String.valueOf( wifiConfigList.get(i).networkId));
		if(wifiConfigList.get(i).SSID.equals(SSID)){//地址相同
    		return wifiConfigList.get(i).networkId;
		}
	}
	return -1;
}

如果需要连接的WIFI没有配置好,即没有保存密码。则为指定名称ssid的WiFi添加密码信息psw,添加成功后返回给其分配的networId,同于连接

未必可用

//添加指定WIFI的配置信息,原列表不存在此SSID
public int AddWifiConfig(List<ScanResult> wifiList,String ssid,String pwd){
	int wifiId = -1;
	for(int i = 0;i < wifiList.size(); i++){
		ScanResult wifi = wifiList.get(i);
		if(wifi.SSID.equals(ssid)){
			Log.i("AddWifiConfig","equals");
			WifiConfiguration wifiCong = new WifiConfiguration();
			wifiCong.SSID = "\""+wifi.SSID+"\"";//\"转义字符,代表"
			wifiCong.preSharedKey = "\""+pwd+"\"";//WPA-PSK密码
			wifiCong.hiddenSSID = false;
			wifiCong.status = WifiConfiguration.Status.ENABLED;
			wifiId = localWifiManager.addNetwork(wifiCong);//将配置好的特定WIFI密码信息添加,添加完成后默认是不激活状态,成功返回ID,否则为-1
			if(wifiId != -1){
				return wifiId;
			}
		}
	}
	return wifiId;
}

开发实战

添加WiFi所需权限

    <!-- 6.0以上打开蓝牙和wifi最好加上定位权限,获取wifi列表要用 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <!-- 获取IP地址 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 访问网络和操作SD卡 加入的两个权限配置 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- 获取网络状态改变的权限 -->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!-- 获取WIFI信息状态的权限 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

判断WiFi是否连接

    public static boolean isWifiEnabled(Context mContext) {
        if (mContext == null) {
            throw new NullPointerException("Global context is null");
        }
        WifiManager wifiMgr = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
        if (wifiMgr.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
            ConnectivityManager connManager = (ConnectivityManager) mContext
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo wifiInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            return wifiInfo.isConnected();
        } else {
            return false;
        }
    }

获取当前连接WiFi的名称

    /**
     * 获取当前连接WIFI的SSID - wifi名称
     */
    public String getWifi_SSID(Context mContext) {
        if (mContext == null) {
            throw new NullPointerException("Global context is null");
        }
        if (isWifiEnabled(mContext)) {
            WifiManager wifi = (WifiManager) mContext.getApplicationContext().getSystemService(WIFI_SERVICE);
            if (wifi != null) {
                WifiInfo wInfo = wifi.getConnectionInfo();
                if (wInfo != null) {
                    String s = wInfo.getSSID();
                    if (s.length() > 2 && s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"') {
                        return s.substring(1, s.length() - 1);
                    }
                }
            }
        }
        return "";
    }

WiFi的IpAddress转为ip地址

获取WifiManager后可获取WiFi的IpAddress值,但是需要转换才能成为最后的ip地址

    public String intToIp(int i) {
        return (i & 0xFF) + "." + ((i >> 8) & 0xFF) + "." + ((i >> 16) & 0xFF) + "." + ((i >> 24) & 0xFF);
    }

获取当前连接WiFi的ip地址

    /**
     * 获取WiFi连接的ip地址
     */
    public String getWifiIp(Context mContext) {
        if (mContext == null) {
            throw new NullPointerException("Global context is null");
        }
        WifiManager wifiMgr = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
        if (isWifiEnabled(mContext)) {
            int ipAsInt = wifiMgr.getConnectionInfo().getIpAddress();
            if (ipAsInt == 0) {
                return null;
            } else {
                return intToIp(ipAsInt);
            }
        } else {
            return null;
        }
    }

获取WiFi列表

    /**
     *权限申请
     * */
    private void registerPermission() {
    	//PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION:是设置权限之后回调函数中用于区别不同权限回调的自定义常量值
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                    100);
        } else {
            getWifiList();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 100) {
            getWifiList();
        }
    }

    /**
     * 获取WiFi列表
     * */
    public List<ScanResult> getWifiList() {
        WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
        List<ScanResult> scanWifiList = wifiManager.getScanResults();
        List<ScanResult> wifiList = new ArrayList<>();
        if (scanWifiList != null && scanWifiList.size() > 0) {
            HashMap<String, Integer> signalStrength = new HashMap<>();
            for (int i = 0; i < scanWifiList.size(); i++) {
                ScanResult scanResult = scanWifiList.get(i);
                Log.e("wifi", "搜索的wifi-ssid:" + scanResult.SSID);
                if (!scanResult.SSID.isEmpty()) {
                    String key = scanResult.SSID + " " + scanResult.capabilities;
                    if (!signalStrength.containsKey(key)) {
                        signalStrength.put(key, i);
                        wifiList.add(scanResult);
                    }
                }
            }
        } else {
            Log.e("wifi", "没有搜索到wifi");
        }
        return wifiList;
    }

获取加密方式

    static final int SECURITY_NONE = 0;
    static final int SECURITY_WEP = 1;
    static final int SECURITY_PSK = 2;
    static final int SECURITY_EAP = 3;

    private int getType(ScanResult result) {
        if (result == null) {
            return SECURITY_NONE;
        }
        String capbility = result.capabilities;
        if (capbility == null || capbility.isEmpty()) {
            return SECURITY_NONE;
        }
        // 如果包含WAP-PSK的话,则为WAP加密方式
        if (capbility.contains("WPA-PSK") || capbility.contains("WPA2-PSK")) {
            return SECURITY_WPA;
        } else if (capbility.contains("WPA2-EAP")) {
            return SECURYTI_EAP;
        } else if (capbility.contains("WEP")) {
            return SECURITY_WEP;
        } else if (capbility.contains("ESS")) {
            // 如果是ESS则没有密码
            return SECURITY_NONE;
        }
        return SECURITY_NONE;
    }

获取 bssid 接入点的地址

    public static String getBSSID() {
        if (wifiManager == null) {
            return null;
        }
        WifiInfo info = wifiManager.getConnectionInfo();
        Log.e("wifidemo", "getBSSID" + info.getBSSID());
        if (info == null) {
            return null;
        }
        return info.getBSSID();
    }

获取网关地址

    public static String getGateway() {
        if (wifiManager == null) {
            return "";
        }
        InetAddress inetAddress = NetWorkUtils.intToInetAddress(wifiManager.getDhcpInfo().gateway);
        if (inetAddress == null) {
            return "";
        }
        return inetAddress.getHostAddress();
    }

获取ip地址

    public static String getIpAddress() {
        if (wifiManager == null) {
            return "";
        }
        InetAddress inetAddress = NetWorkUtils.intToInetAddress(wifiManager.getConnectionInfo().getIpAddress());
        if (inetAddress == null) {
            return "";
        }
        return inetAddress.getHostAddress();
    }

获取mac地址

    public static String getMacAddress() {
        if (wifiManager == null) {
            return "";
        }
        return wifiManager.getConnectionInfo().getMacAddress();
    }

根据ssid判断该wifi是否连接

    public boolean isCurrentConnect(String ssID) {
        ssID = "\"" + ssID + "\"";
        WifiInfo info = getWifiInfo();
        //当前的ssid为空,未连接wifi
        if (TextUtils.isEmpty(info.getSSID())) {
            return false;
        } else {//已连接
            String tempSSID = info.getSSID();
            return tempSSID.equals(ssID);
        }
    }

根据给定的ssid信号量和总级别,判断当前信号量,在什么级别

    public static int getSignalNumsLevel(int rssi, int numLevels) {
        if (wifiManager == null) {
            return -1;
        }
        return WifiManager.calculateSignalLevel(rssi, numLevels);
    }

刷新wifi列表

    public void refreshLocalWifiListData() {
        /*逻辑说明:
        1. 从扫描结果中将已经连接的wifi添加到wifi列表中
        2. 从所有WiFilist中将已经添加过的已经连接的WiFi移除
        3. 将剩余的WiFi添加到WiFilist中
        实现了已经连接的WiFi处于wifi列表的第一位*/

        //得到扫描结果
        mWifiList.clear();
        List<ScanResult> tmpList = mWifiManager.getScanResults();
        for (ScanResult tmp : tmpList) {
            if (isGivenWifiConnect(tmp.SSID)) {
                mWifiList.add(tmp);
            }
        }
        //从wifi列表中删除已经连接的wifi
        for (ScanResult tmp : mWifiList) {
            tmpList.remove(tmp);
        }
        mWifiList.addAll(tmpList);
    }

创建WifiConfiguration

 public WifiConfiguration creatWifiConfiguration(String ssid, String password) {
        ScanResult currentWIFI = null;
        WifiSecutityEnum type = WifiSecutityEnum.NOON;
        for (ScanResult temp : getmWifiList()) {
            if (temp.SSID.equals(ssid)) {
                currentWIFI = temp;
            }
        }
        if (currentWIFI != null) {
            Log.i(TAG, "creatWifiConfiguration: " + currentWIFI.toString());
            type = getWifiSecurityMode(currentWIFI.capabilities);
        }
 
        WifiConfiguration config = new WifiConfiguration();
        config.allowedAuthAlgorithms.clear();
        config.allowedGroupCiphers.clear();
        config.allowedKeyManagement.clear();
        config.allowedPairwiseCiphers.clear();
        config.allowedProtocols.clear();
        config.SSID = "\"" + ssid + "\"";
        //如果当前连接的wifi被保存了密码,清除wifi保存信息
        WifiConfiguration tempConfig = isWifiSave(ssid);
        if (tempConfig != null) {
            mWifiManager.removeNetwork(tempConfig.networkId);
            mWifiManager.saveConfiguration();
        }
 
        switch (type) {
            case NOON:
                config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                break;
            case WEP:
                config.hiddenSSID = true;
                config.wepKeys[0] = "\"" + password + "\"";
                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;
                break;
            case WPA_AND_WPA2:
                config.preSharedKey = "\"" + password + "\"";
                config.hiddenSSID = true;
                config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
                config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
                config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
                config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
                // config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
                config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
                config.status = WifiConfiguration.Status.ENABLED;
                break;
        }
        return config;
    }

判断指定的wifi是否保存

public WifiConfiguration isWifiSave(String SSID) {
    if (mWifiConfigurations != null) {
        for (WifiConfiguration existingConfig : mWifiConfigurations) {
            if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
                return existingConfig;
            }
        }
    }
    return null;
}

断开连接

 public void disConnectWifi(){
        wifiManager.disconnect();
    }

断开指定ID的网络

 public void disConnectionWifi(int netId) {
        wifiManager.disableNetwork(netId);
        wifiManager.disconnect();
    }

扩展 - 获取本地计算机信息

    public void wifiLocalHost() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                InetAddress address = null;
                try {
                    address = InetAddress.getLocalHost();
                    System.out.println("计算机名" + address.getHostName());
                    System.out.println("IP地址" + address.getHostAddress());
                    byte[] bytes = address.getAddress();//获取字节数组形式的IP地址  
                    System.out.println("字节数组形式的Ip" + Arrays.toString(bytes));
                    System.out.println(address);//直接输出InetAddress对象  
                    //根据机器名获取InetAddress实例  
                    InetAddress address3 = null;
                    address3 = InetAddress.getByName("192.168.249.1");
                    System.out.println("计算机名" + address3.getHostName());
                    System.out.println("IP地址" + address3.getHostAddress());
                    /* get www.baidu.com's ip */
                    InetAddress remAdd = null; //取得远程InetAddress对象
                    remAdd = InetAddress.getByName("www.baidu.com");
                    System.out.println("本机IP地址:" + address.getHostAddress()); //得到本地IP地址
                    System.out.println("百度IP地址:" + remAdd.getHostAddress()); //得到百度IP地址
                    System.out.println("本机是否可达:" + address.isReachable(10000)); //10000是超时时间,10s
                    //很多情况是,某一域名对应的主机IP是可能有多个的,我们也可以一一的取回来。如下:
                    // 百度可能有多个IP地址,解析回来,所以我们可以用一个数组装起来
                    InetAddress[] addrs = InetAddress.getAllByName("www.baidu.com");
                    if (addrs != null && addrs.length > 0) {
                        for (InetAddress addr : addrs) {
                            System.out.println("--->" + addr.getHostAddress());
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }).start();
    }