由于开发须要在应用内部实现wifi链接,结合网上的资料,实现链接wifi的仍是比较简单,可是对于链接匿名wifi,却鲜有说起,因此在此分享下。java
首先介绍下wifi开发相关的一些基础概念和工具类等,若是对wifi已经有过接触的同窗能够直接跳过看下一节。android
Android中要使用系统功能通常都要申请权限,这里wifi须要的权限有api
<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"/> // 须要系统权限 [定位权限]
复制代码
由于能够利用wifi进行定位,因此这里须要申请定位权限,在6.0以上设备,定位权限须要主动申请。bash
类名 | 功能 |
---|---|
WifiManager | wifi统一管理类,进行各类wifi操做 |
WifiInfo | 描述当前链接的wifi热点信息 |
WifiConfiguration | wifi网络配置信息 |
ScanResult | 描述扫描出的wifi热点的信息 |
WifiManager类是framework层暴露的api,用来管理wifi。网络
val mWifiManager = mContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
复制代码
经过他能够获得:1.已经配置的网络列表。2.当前链接的wifi。3.扫描到的wifi。4.以及一些常量表示广播的意图等ide
ScanResult类用于存放wifi扫描结果信息,主要有如下内容:工具
属性 | 描述 |
---|---|
SSID | 描述wifi热点的名称,就是你们搜索到的直接名称,如ChinaNet |
BSSID | 姑且理解成热点的mac地址,但实际有所不一样 |
networkID | 数字型的id |
level | 描述wifi信号强弱的值,值是负数,绝对值越小,信号越强 |
capabilities | 如加密方式,如WEP |
wifi状态的改变是会致使广播事件的发生。加密
val filter = IntentFilter()
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION) //监听wifi状态改变
filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) //监听扫描到wifi列表改变
复制代码
private val mReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (TextUtils.isEmpty(action)) return
when (action) {
WifiManager.WIFI_STATE_CHANGED_ACTION -> {
}
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION -> {
}
}
}
}
复制代码
WifiManager之中有当前状态的enum类型,能够看下表:spa
名称 | 描述 |
---|---|
WIFI_STATE_DISABLING | wifi正在关闭 |
WIFI_STATE_DISABLED | wifi关闭 |
WIFI_STATE_ENABLING | wifi正在开启 |
WIFI_STATE_ENABLED | wifi开启 |
WIFI_STATE_UNKNOWN | wifi未知 |
链接wifi我大体分为如下几步:code
public static void connectNewWifi(Context mContext, WifiConfiguration wifiConfiguration) {
WifiManager wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
int networkId = wifiManager.addNetwork(wifiConfiguration);
wifiManager.enableNetwork(networkId, true);
}
复制代码
因此重点是怎样建立wifiConfigruation,不一样的加密方式的wifi,建立过程也不太同样:
public WifiConfiguration createWifiConfig(String SSID, @WifiCipherType int wifiCipherType, String password) {
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = convertToQuotedString(SSID);
switch (wifiCipherType) {
case WifiCipherType.SECURITY_NONE:
wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
break;
case WifiCipherType.SECURITY_WEP:
wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
if (!TextUtils.isEmpty(password)) {
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 WifiCipherType.SECURITY_PSK:
wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
if (!TextUtils.isEmpty(password)) {
if (password.matches("[0-9A-Fa-f]{64}")) {
wifiConfiguration.preSharedKey = password;
} else {
wifiConfiguration.preSharedKey = '"' + password + '"';
}
}
break;
case WifiCipherType.SECURITY_EAP:
wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
wifiConfiguration.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
wifiConfiguration.enterpriseConfig = new WifiEnterpriseConfig();
int eapMethod = 0;
int phase2Method = 0;
wifiConfiguration.enterpriseConfig.setEapMethod(eapMethod);
wifiConfiguration.enterpriseConfig.setPhase2Method(phase2Method);
if (!TextUtils.isEmpty(password)) {
wifiConfiguration.enterpriseConfig.setPassword(password);
}
break;
default:
break;
}
return wifiConfiguration;
}
复制代码
至此wifi就链接完成了,而后能够在广播中获取链接结果。相应的wifi配置信息会被保存在/data/misc/wifi/wpa_supplicant.conf
中:
network={
ssid="test"
psk="88888888"
key_mgmt=WPA-PSK
disabled=1
id_str="%7B%22creatorUid%22%3A%221000%22%2C%22configKey%22%3A%22%5C%22test%5C%22WPA_PSK%22%7D"
}
复制代码
匿名wifi相较于普通wifi,不一样之处在于不会广播其SSID,因此就不能被直接扫描到,须要咱们输入wifi的SSID来主动进行扫描,先来看下匿名wifi的配置信息:
network={
ssid="test2"
scan_ssid=1
bssid=56:28:f8:fa:f8:a0
psk="44444444"
key_mgmt=WPA-PSK
disabled=1
id_str="%7B%22creatorUid%22%3A%221000%22%2C%22configKey%22%3A%22%5C%22test2%5C%22WPA_PSK%22%7D"
}
复制代码
能够看到,多了一个scan_ssid属性,查看WifiConfiguration
,确实有一个属性能够设置
/**
* This is a network that does not broadcast its SSID, so an
* SSID-specific probe request must be used for scans.
*/
public boolean hiddenSSID;
复制代码
因此在建立WifiConfiguration的时候多设置下这个属性就好了:
configuration.hiddenSSID = true
复制代码