眼看自己來這個(gè)公司的第一個(gè)項(xiàng)目,也是公司的核心項(xiàng)目即將上線了贮匕,細(xì)數(shù)一番姐仅,已有半年之久,中間也做了一些小項(xiàng)目粗合,忍不住驚嘆了一下萍嬉,這么久了居然沒有做下筆記,真是罪過罪過隙疚。記得學(xué)習(xí)android之時(shí)就喜歡記下開發(fā)知識(shí)點(diǎn)壤追,開發(fā)技巧。在我看來供屉,總結(jié)可以使自己穩(wěn)步進(jìn)步行冰。趁項(xiàng)目稍微空余時(shí)期溺蕉,總結(jié)一下,涉及到WIFI開發(fā)相關(guān)的東西相當(dāng)之多悼做,這里主要記錄一下項(xiàng)目中用到的相關(guān)知識(shí)疯特。【感謝博友的資料http://smallwoniu.blog.51cto.com/3911954/1334951】
-
主要類與接口
1. WifiManager
wifi連接統(tǒng)一管理類肛走,獲取WIFI網(wǎng)卡的狀態(tài)(WIFI網(wǎng)卡的狀態(tài)是由一系列的整形常量來表示的)
2. ScanResult
主要用來描述已經(jīng)檢測(cè)出的接入點(diǎn)漓雅,包括接入點(diǎn)的地址,接入點(diǎn)的名稱朽色,身份認(rèn)證邻吞,頻率,信號(hào)強(qiáng)度等信息葫男。其實(shí)就是通過wifi 硬件的掃描來獲取一些周邊的wifi 熱點(diǎn)的信息抱冷。
3. WifiConfiguration
Wifi網(wǎng)絡(luò)的配置,包括安全設(shè)置等梢褐,在我們連通一個(gè)wifi 接入點(diǎn)的時(shí)候旺遮,需要獲取到的一些信息。主要包含四個(gè)屬性:
BSSID:
BSS是一種特殊的Ad-hoc LAN(一種支持點(diǎn)對(duì)點(diǎn)訪問的無線網(wǎng)絡(luò)應(yīng)用模式)的應(yīng)用盈咳,一個(gè)無線網(wǎng)絡(luò)至少由一個(gè)連接到有線網(wǎng)絡(luò)的AP和若干無線工作站組成耿眉,這種配置稱為一個(gè)基本服務(wù)裝置。一群計(jì)算機(jī)設(shè)定相同的 BSS名稱猪贪,即可自成一個(gè)group跷敬,而此BSS名稱,即所謂BSSID热押。通常西傀,手機(jī)WLAN中,bssid其實(shí)就是無線路由的MAC地址桶癣。
networkid:網(wǎng)絡(luò)ID拥褂。
PreSharedKey:無線網(wǎng)絡(luò)的安全認(rèn)證模式。
SSID:SSID(Service SetIdentif)用于標(biāo)識(shí)無線局域網(wǎng)牙寞,SSID不同的無線網(wǎng)絡(luò)是無法進(jìn)行互訪的饺鹃。
4. WifiInfo
wifi無線連接的描述,包括(接入點(diǎn)间雀,網(wǎng)絡(luò)連接狀態(tài)悔详,隱藏的接入點(diǎn),IP地址惹挟,連接速度茄螃,MAC地址,網(wǎng)絡(luò)ID连锯,信號(hào)強(qiáng)度等信息)归苍。這里簡(jiǎn)單介紹一下WifiManager中常用的方法:
方法名 | 注釋 |
---|---|
getSSID() | 獲得SSID(熱點(diǎn)名稱) |
getBSSID() | 獲取BSSID |
getDetailedStateOf() | 獲取客戶端的連通性 |
getHiddenSSID() | 獲得SSID 是否被隱藏 |
getIpAddress() | 獲取IP 地址 |
getLinkSpeed() | 獲得連接的速度(我測(cè)試時(shí)發(fā)現(xiàn)沒什么卵用- -) |
getMacAddress() | 獲得Mac 地址 |
getRssi() | 獲得802.11n 網(wǎng)絡(luò)的信號(hào) |
在AndroidManifest.xml進(jìn)行對(duì)WIFI操作的權(quán)限設(shè)置
<!-- 以下是使用wifi訪問網(wǎng)絡(luò)所需的權(quán)限 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
-
使用方法
1.WIFI開發(fā) 我想第一點(diǎn)首先是如何打開wifi開關(guān)
打開之前先獲取WifiManager 對(duì)象用狱,通過該對(duì)象的isWifiEnabled():boolean 方法來獲取當(dāng)前wifi的開啟情況,如果未打開拼弃,則執(zhí)行打開wifi開關(guān)操作
WifiManager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (夏伊!mWifiManager.isWifiEnabled()) {//wifi未打開 執(zhí)行打開操作
mWifiManager.setWifiEnabled(true);//同樣的執(zhí)行關(guān)閉操作的話: mWifiManager.setWifiEnabled(false);
}
2. WIFI打開之后自然是執(zhí)行掃描操作,搜索周邊范圍內(nèi)的熱點(diǎn)信息
/**
* 掃描熱點(diǎn),掃描時(shí)耗時(shí)操作吻氧,如果界面中需要展示進(jìn)度條的話溺忧,建議將掃描操作放在子線程中操作
*/
mWifiManager.startScan();
// 得到掃描結(jié)果
List<ScanResult> mWifiList = mWifiManager.getScanResults();
// 得到配置好的網(wǎng)絡(luò)連接,列表中可能出現(xiàn)重復(fù)的熱點(diǎn),并且可能是ssid為空的熱點(diǎn)盯孙,根據(jù)需求情況 自行過濾
mWifiConfiguration = mWifiManager.getConfiguredNetworks();
// 查看掃描結(jié)果
public StringBuilder lookUpScan() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < mWifiList.size(); i++) {
stringBuilder
.append("Index_" + new Integer(i + 1).toString() + ":");
// 將ScanResult信息轉(zhuǎn)換成一個(gè)字符串包
// 其中把包括:BSSID砸狞、SSID、capabilities镀梭、frequency、level
stringBuilder.append((mWifiList.get(i)).toString());
stringBuilder.append("/n");
}
return stringBuilder;
}
3. 獲取正在連接中的SSID
mWifiInfo.getSSID()
/**
* 獲得當(dāng)前連接的熱點(diǎn) 用上面方法 可能獲得的結(jié)果為: "0x" 或 "<unknown ssid>"
* 猜測(cè)是因?yàn)閣ifiInfo的問題踱启,因此每次去getSSID()的時(shí)候需要獲得最新的wifiInfo對(duì)象
*/
4. 如果需要的話 對(duì)熱點(diǎn)信號(hào)強(qiáng)度進(jìn)行排序
//將搜索到的wifi根據(jù)信號(hào)從強(qiáng)到弱進(jìn)行排序
private List<ScanResult> sortByLevel(List<ScanResult> list) {
ScanResult temp = null;
for (int i = 0; i < list.size(); i++)
for (int j = 0; j < list.size(); j++) {
if (list.get(i).level > list.get(j).level) //level屬性即為強(qiáng)度
{
temp = list.get(i);
list.set(i, list.get(j));
list.set(j, temp);
}
}
return list;
}
5.連接到熱點(diǎn)
/**
* 眾所周知 熱點(diǎn)的加密分為三種情況:1沒有密碼 2用wep加密 3用wpa加密
*/
public static WifiConfiguration CreateWifiInfo(String SSID, String Password, 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);
}
if (Type == 1) //WIFICIPHER_NOPASS
{
/* config.wepKeys[0] = "";//連接無密碼熱點(diǎn)時(shí)加上這兩句會(huì)出錯(cuò)
config.wepTxKeyIndex = 0;*/
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
}
if (Type == 2) //WIFICIPHER_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;
}
if (Type == 3) //WIFICIPHER_WPA
{
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;
}
return config;
}
// 添加一個(gè)網(wǎng)絡(luò)并連接
public static boolean addNetwork(WifiConfiguration wcg) {
int wcgID = mWifiManager.addNetwork(wcg);
boolean b = mWifiManager.enableNetwork(wcgID, true);
System.out.println("a--" + wcgID);
System.out.println("b--" + b);
if (b) {
linkingID = wcgID;
}
return b;
}
//連接方式
WifiConfiguration wifiConfiguration = CreateWifiInfo(SSID, Password, Type);
boolean flag = addNetwork(wifiConfiguration);//連接網(wǎng)絡(luò)
/**
*flag 返回true 并不能代表熱點(diǎn)連接成功报账,但是返回false一定代表連接不成功
*當(dāng)密碼位數(shù)不對(duì)時(shí)也會(huì)直接返回false,因此不能用該參數(shù)來判別是否連接成功
*這也是我在項(xiàng)目中碰到的一個(gè)難題
*/
項(xiàng)目中涉及到wifi切換連接埠偿,這個(gè)時(shí)候就需要監(jiān)聽熱點(diǎn)切換情況透罢,這是個(gè)難點(diǎn)。不同設(shè)備的熱點(diǎn)連接速度也不一致冠蒋,我的做法是啟動(dòng)一個(gè)定時(shí)任務(wù)羽圃,當(dāng)wifi進(jìn)行切換時(shí)先保存oldCurrentSSID,gonaLinkSSID來保存目的連接SSID抖剿,然后定時(shí)的去讀取當(dāng)前連接中的ssid:mWifiInfo.getSSID(),來實(shí)時(shí)的監(jiān)聽當(dāng)前熱點(diǎn)情況朽寞,如果當(dāng)前熱點(diǎn)與oldCurrentSSID不等,并且等于gonaLinkSSID,即代表熱點(diǎn)切換成功斩郎。這邊需要考慮的是這個(gè)定時(shí)的長(zhǎng)度脑融,因?yàn)閣ifi沒有正在連接的狀態(tài),所以這邊無法準(zhǔn)確知道何時(shí)連接完畢缩宜,所以這里只能給個(gè)大概的時(shí)間肘迎,同時(shí)在該時(shí)間內(nèi)如果滿足連接成功狀態(tài),即可提前取消定時(shí)刷新任務(wù)锻煌。同時(shí)需要結(jié)合廣播(當(dāng)網(wǎng)絡(luò)狀態(tài)變化時(shí)系統(tǒng)會(huì)發(fā)出一條廣播)來得到最準(zhǔn)確的值妓布。
</br>
6. 斷開指定連接
// 斷開指定ID的網(wǎng)絡(luò),這邊的id在添加連接時(shí)獲取 int wcgID = mWifiManager.addNetwork(wcg);
public static void disconnectWifi(int netId) {
if(0 == linkingID ){
return;
}
mWifiManager.disableNetwork(linkingID);
mWifiManager.disconnect();
LogUti.i("info", "斷開連接 id" + linkingID);
}
//有些情況下我們可能并不方便拿到那個(gè)id,這個(gè)時(shí)候可以投機(jī)取巧的地方是隨便連接一個(gè)不能連接成功的ssid宋梧,當(dāng)ssid切換的時(shí)候 wifi會(huì)先自動(dòng)斷開當(dāng)前連接的熱點(diǎn)才去連接目標(biāo)ssid