[Android WIFI开发]

前言

在Android应用层的开发中,使用到wifi相关知识点的地方并不多,所以之前对wifi开发并不熟悉,最近接到的两个硬件项目都有用到wifi并且知识点越来越深入,所以有必要记一下笔记,做一些注释。

基本使用

1.权限

Android中要使用系统功能一般都要申请权限,在6.0上可能还要手动申请权限,这里wifi需要的权限有

    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> // 需要系统权限 [定位权限]

其中在6.0以上设备,定位权限需要主动申请,并且如果要获取扫描wifi列表需要打开系统的定位开关。

2. WiFi相关API

WIFI相关API

ScanResult类用于存放wifi扫描结果信息,包含ssid(wifi名称), bssid(网络接入点地址),capabilities(加密类型),frequency(传输频率),level(信号强度)等。这里的解释并不太标准,但是对应功能很形象,如果你要了解更多,可以去具体的查阅资料。

WifiConfiguration类用于存放wifi的配置信息。包括wifi的密码,加密类型,网络id(用于连接wifi)等。他的几个子类分别对应秘钥加密方式,安全协议等,这些在设置wifi配置的时候会被用到

wifiinfo类用来描述wifi属性和连接状态。暴露了一些方法给开发者调用。getBSSID(), getMacAddress(), getIpAddress(),getSSID()等

WifiManager类是framework层暴露的api,用来管理wifi。通过调用 Context.getSystemService(Context.WIFI_SERVICE)可以得到类的实例。通过他可以得到:1.已经配置的网络列表。2.当前连接的wifi。3.扫描到的wifi。4.以及一些常量表示广播的意图等

3. wifi状态及开关

/**
 * 判断wifi是否打开
 * <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>}</p>
 *
 * @return {@code true}: 是<br>{@code false}: 否
 */
public static boolean getWifiEnabled() {
    @SuppressLint("WifiManagerLeak")
    WifiManager wifiManager = (WifiManager) Utils.getApp().getSystemService(Context.WIFI_SERVICE);
    return wifiManager.isWifiEnabled();
}

/**
 * 打开或关闭wifi
 * <p>需添加权限 {@code <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>}</p>
 *
 * @param enabled {@code true}: 打开<br>{@code false}: 关闭
 */
public static void setWifiEnabled(final boolean enabled) {
    @SuppressLint("WifiManagerLeak")
    WifiManager wifiManager = (WifiManager) Utils.getApp().getSystemService(Context.WIFI_SERVICE);
    if (enabled) {
        if (!wifiManager.isWifiEnabled()) {
            wifiManager.setWifiEnabled(true);
        }
    } else {
        if (wifiManager.isWifiEnabled()) {
            wifiManager.setWifiEnabled(false);
        }
    }
}

4. 扫描wifi

 /**
 *
 * 获取WIFI列表
 * <p>需要权限{@code <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>}</p>
 * <p>注意Android6.0上需要主动申请定位权限,并且打开定位开关</p>
 *
 * @param context 上下文
 * @return wifi列表
 */
public static List<ScanResult> getWifiList(Context context) {
    WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    List<ScanResult> scanResults = wm.getScanResults();

    Collections.sort(scanResults, new Comparator<ScanResult>() {
        @Override
        public int compare(ScanResult scanResult1, ScanResult scanResult2) {
            return scanResult2.level - scanResult1.level;
        }
    });
    return scanResultsCopy;
}

 /**
 * 获取当前链接的WiFi信息
 *
 * @param context 上下文
 * @return 当前wifi数据
 */
public static WifiInfo getCurrentWifi (Context context) {
    WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    return wm.getConnectionInfo();
}


public static String getWifiEncryptTypeStr (String capabilitie) {
    if (TextUtils.isEmpty(capabilitie)) return null;

    String encryptType;

    if (capabilitie.contains("WPA") && capabilitie.contains("WPA2")) {
        encryptType = "WPA/WPA2 PSK";
    } else if (capabilitie.contains("WPA2")) {
        encryptType = "WPA2 PSK";
    } else if (capabilitie.contains("WPA")) {
        encryptType = "WPA PSK";
    } else if (capabilitie.contains("WEP")) {
        encryptType = "WEP";
    } else {
        encryptType = "NONE";
    }

    return encryptType;
}

/**
 * wifi加密方式有5种
 * 0 - WPA/WPA2 PSK
 * 1 - WPA2 PSK
 * 2 - WPA PSK
 * 3 - WEP
 * 4 - NONE
 * @param capabilitie
 * @return
 */
public static int getWifiEncryptType (String capabilitie) {
    if (TextUtils.isEmpty(capabilitie)) return -1;

    int encryptType;

    if (capabilitie.contains("WPA") && capabilitie.contains("WPA2")) {
        encryptType = 0;
    } else if (capabilitie.contains("WPA2")) {
        encryptType = 1;
    } else if (capabilitie.contains("WPA")) {
        encryptType = 2;
    } else if (capabilitie.contains("WEP")) {
        encryptType = 3;
    } else {
        encryptType = 4;
    }

    return encryptType;
}

5. 连接wifi

 /**
 * @des 连接已经保存过配置的wifi
 * @param context
 * @param ssid
 */
public static void connectWifi (Context context, String ssid) {

    Log.d(TAG, "connectWifi: 去连接wifi: " + ssid);

    if (!getWifiEnabled()) return;

    WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    WifiConfiguration wc = new WifiConfiguration();

    wc.SSID = "\"" + ssid + "\"";

    WifiConfiguration configuration = getWifiConfig(context, ssid);
    if (configuration != null) {
        wm.enableNetwork(configuration.networkId, true);
    }

}

/**
 * @des 连接没有配置过的wifi
 * @param context
 * @param ssid
 * @param password
 * @param encryptType
 */
public static void connectWifi (Context context, String ssid, String password, int encryptType) {

    Log.d(TAG, "connectWifi: 去连接wifi: " + ssid);

    if (!getWifiEnabled()) return;

    WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    WifiConfiguration wc = new WifiConfiguration();
    wc.allowedAuthAlgorithms.clear();
    wc.allowedGroupCiphers.clear();
    wc.allowedKeyManagement.clear();
    wc.allowedPairwiseCiphers.clear();
    wc.allowedProtocols.clear();

    wc.SSID = "\"" + ssid + "\"";

    WifiConfiguration configuration = getWifiConfig(context, ssid);
    if (configuration != null) {
        wm.removeNetwork(configuration.networkId);
    }

    switch (encryptType) {
        case 4://不加密
            wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            break;

        case 3://wep加密
            wc.hiddenSSID = true;
            wc.wepKeys[0] = "\"" + password +"\"";
            wc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
            wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);

            break;
        case 0: //wpa/wap2加密
        case 1: //wpa2加密
        case 2: //wpa加密

            wc.preSharedKey = "\"" + password + "\"";
            wc.hiddenSSID = true;
            wc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
            wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            wc.status = WifiConfiguration.Status.ENABLED;
            break;
    }

    int network = wm.addNetwork(wc);
    wm.enableNetwork(network, true);
}

public static void disConnectWifi (Context context, int networkId) {
    WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    wm.disableNetwork(networkId);
    wm.disconnect();
}

6. 获取和清除WIFI配置

/**
 * @des 清除wifi配置信息
 * @param context
 * @param ssid
 */
public static void clearWifiInfo(Context context, String ssid) {

    Log.d(TAG, "clearWifiInfo: 清除WIFI配置信息: " + ssid);

    WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

    String newSSID = "\"" + ssid + "\"";

    if (!(ssid.startsWith("\"") && ssid.endsWith("\""))) {
        newSSID = "\"" + ssid + "\"";
    } else {
        newSSID = ssid;
    }

    WifiConfiguration configuration = getWifiConfig(context, newSSID);
    configuration.allowedAuthAlgorithms.clear();
    configuration.allowedGroupCiphers.clear();
    configuration.allowedKeyManagement.clear();
    configuration.allowedPairwiseCiphers.clear();
    configuration.allowedProtocols.clear();

    if (configuration != null) {

        wm.removeNetwork(configuration.networkId);
        wm.saveConfiguration();
    }
}

public static WifiConfiguration getWifiConfig (Context context, String ssid) {

    Log.d(TAG, "getWifiConfig: 获取wifi配置信息: " + ssid);

    if (TextUtils.isEmpty(ssid)) return null;

    String newSSID;

    if (!(ssid.startsWith("\"") && ssid.endsWith("\""))) {
        newSSID = "\"" + ssid + "\"";
    } else {
        newSSID = ssid;
    }

    WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    List<WifiConfiguration> configuredNetworks = wm.getConfiguredNetworks();

    for (WifiConfiguration configuration : configuredNetworks) {
        if (newSSID.equalsIgnoreCase(configuration.SSID)) {
            return configuration;
        }
    }

    return null;
}

高级用法

1. 监听wifi状态的变化并刷新wifi列表和连接状态

2. 5Gwfif和2.4Gwifi

踩坑记录

1. wifi的ssid是带有"",所以你如果要判空是不行的,并且在连接wifi的时候要手动给ssid加上""。

2. 前文已经说了Android6.0以上要想扫描到wifi需要开启权限和手机的定位功能,不然得到的列表为空。

3. wifi的秘钥安全模式网上并没有人给出标准的答案,各个手机厂商的wifi系统上也都不一样,对于我们开发者而言,主要有5种方式也可以总结为3中:NONE(无密码模式), WEP(安全性较低), WAP PSK, WAP2 PSK, WPA/WPA2 PSK(这三种安全性较高)。需要注意的是通过capabilitie属性得到的字符串是类似 [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS] 这样的,因为wifi的加密方式是安全模式+密码加密类型组合的方式。你要通过string.contains()方法解析出其中的安全模式,上文的扫描wifi中有解析的代码。

4. 扫描列表中ssid可能为空或"",一般要剔除掉,而且wifi列表一般是根据信号强度排序。也有可能列表中出现同名的wifi,我之前遇到是因为现在的路由器同时支持5G wifi和2.4G wifi,两个wifi属于不同的频段。

5. wifi是可以设置为隐藏wifi的,设置为隐藏wifi后不能被扫描到,但是可以通过直接输入ssid和秘钥的方式连接上。

后记

Android 6.0 中的 Wifi 连接

WiFi加密方式有哪些?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容