由於開發須要在應用內部實現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
複製代碼