需求:本人搞物聯(lián)網(wǎng)味混,wifi需要上網(wǎng),前提需要先讓wifi模組連接上路由器,存在wifi模組配網(wǎng)的過程。
有兩種配網(wǎng)模式质欲,
SmartLink,一種使用UDP廣播技術實現(xiàn)的一種快速配網(wǎng)的技術,改技術有一個致命的缺陷展姐,當路由不支持UPD廣播擂达,或者被封禁的時候,改技術無法使用了。
SoftAP涯穷,這種比較傳統(tǒng)的方式,先讓手機與wifi模組建立的熱點進行連接起意,將需要連接的wifi路由 ssid與password告知wifi模組后套菜,讓wifi模組去連接。兼容性很好逗柴,貴在比較復雜挟冠,操作步驟多嫌吠。
對于Android系統(tǒng)來說,因為可以對wifi進行操作邢滑,可以做到與SmartLink一樣的快捷,更多的交給后臺處理完成配網(wǎng);將使用到WifiManager這個系統(tǒng)類救鲤;
坑一:WifiManager獲取時產(chǎn)生內存泄露
引用前輩的帖子久窟, http://www.reibang.com/p/5d96983fc6db
坑二:addNetwork返回-1
相信很多人在這塊開發(fā)的時候都不會自己一個一個字母的敲出來,網(wǎng)上copy一下完成了本缠。
基本上網(wǎng)上的代碼就這么一寫斥扛,注意紅框中的兩個方法;
你會發(fā)現(xiàn)在很多請情況下addNetword都是返回-1丹锹;這將會使enableNetword 無法連接到指定的wifi中稀颁;
官方APP描述,新網(wǎng)絡描述添加到已配置網(wǎng)絡集楣黍。也就是說這個方法用于新的匾灶,未連接過的wifi;適當換成
//判斷wifi曾經(jīng)是不是連接過
WifiConfiguration tempConfig = isExsits(ssid);
if (tempConfig != null) {
boolean enabled = wifiManager.enableNetwork(tempConfig.networkId, true);
Log.d(TAG, "enableNetwork status enable=" + enabled);
} else {
int netID = wifiManager.addNetwork(wifiConfig);
boolean enabled = wifiManager.enableNetwork(netID, true);
Log.d(TAG, "enableNetwork status enable=" + enabled);
}
private WifiConfiguration isExsits(String SSID) {
if (wifiManager != null) {
List<WifiConfiguration> existingConfigs = wifiManager
.getConfiguredNetworks();
for (WifiConfiguration existingConfig : existingConfigs) {
if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
return existingConfig;
}
}
}
return null;
}
坑三:掃描獲取手機附近wifi列表返回 size=0
/**
* 獲取wifi列表
*
* @return
*/
private List<ScanResult> getWifiList() {
// 開始掃描
wifiManager.startScan();
// 得到掃描結果
return wifiManager.getScanResults();
}
坑四:連接沒有密碼的AP熱點
把taget版本支持到28之后租漂,發(fā)現(xiàn)連接AP熱點怎么也連不上了阶女,經(jīng)過一段時間的測試,發(fā)現(xiàn)AP熱點沒有密碼的時候哩治, addnetword方法必然返回-1. 日了啊
搞了蠻久秃踩,WifiConfiguration的配置得增加上 “無密碼” “WPA” “WEP”加密方式的配置,順利搞定业筏;
if (/*Open network*/) {
// No security
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
wifiConfig.allowedAuthAlgorithms.clear();
wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
} else if (/*WPA*/ || /*WPA2*/) {
//WPA/WPA2 Security
wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
wifiConfig.preSharedKey = "\"".concat(password).concat("\"");
} else if (/*WEP*/) {
// WEP Security
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
wifiConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
wifiConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
wifiConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
wifiConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
if (getHexKey(password)) wifiConfig.wepKeys[0] = password;
else wifiConfig.wepKeys[0] = "\"".concat(password).concat("\"");
wifiConfig.wepTxKeyIndex = 0;
}
在Android 6.0之后憔杨,必須打開GPS才可以獲取到wifi列表,想辦法讓客戶打開GPS開關把蒜胖,完美解決芍秆;
(目前miui 系統(tǒng),還是無法正常連接到指定的wifi翠勉,打印log顯示已經(jīng)連接了,實際手機沒有切換過去霉颠,不知道什么問題对碌,有遇到這樣問題的,希望可以指導下我蒿偎;)引用評論3樓的方法朽们,在連接之前先disconnect,再連接诉位,解決骑脱;感謝!2钥贰叁丧!
2019-11-04 繼續(xù)補充
坑五 關于 MIUI、華為 disconnect之后 積極連接其他wifi問題的處理
小米與華為手機斷開連接后,會非秤德Γ快速的連接曾經(jīng)連接過的WIFI蚊锹,這時 enableNetwork 方法壓根搶不過系統(tǒng),導致連接AP 熱點失敗稚瘾。
引用前輩一篇文章牡昆,代碼寫得比較全了,里面注釋也提到了這個問題 摊欠。
https://juejin.im/post/5b18c3d1f265da6e3c6b93da
說下我解決這個問題的過程丢烘,網(wǎng)上其實有一些極端的方法可以解決這個問題。
1些椒、WiFiManager.disableNetwork()
使用 disableNetwork 方法播瞳,該方法是講已經(jīng)保存的wifi進行禁用,禁用之后摊沉,系統(tǒng)就不會自動的去連接這些連接過的WIFI狐史,解決這個問題(華為測試過之后);
(小米去測試的時候就惡心了说墨,MIUI系統(tǒng)每次操作WIFI都會提示用戶骏全,是否允許操作wifi,也就是說你保存了100個wifi的配置你得點100次允許尼斧,了勒個去=薄!9卓谩)
2楼咳、WifiManager.WifiLock
沒法子,又得去爬谷歌的API文檔了烛恤,英語不好母怜,折磨。缚柏。苹熏。
主要使用以上三個方法,給WIFI加鎖币喧。
public class WifiLocKManager {
// 定義WifiManager對象
private WifiManager mWifiManager;
// 定義一個WifiLock
private WifiManager.WifiLock mWifiLock;
private Context context;
public WifiLocKManager(Context context) {
// 取得WifiManager對象
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
//第一種方式
creatWifiLock("WifiLocKManager");
//第二種方式
//解析一下三個常量
//WIFI_MODE_SCAN_ONLY 在此Wi-Fi鎖定模式下轨域,Wi-Fi將保持活動狀態(tài),但是唯一受支持的操作是啟動掃描以及隨后報告掃描結果杀餐。
// 不會嘗試自動連接到記住的訪問點干发,也不會自動執(zhí)行定期掃描以查找記住的訪問點。在這種模式下史翘,應用程序必須明確請求掃描枉长。
//····································································
//WIFI_MODE_FULL_LOW_LATENCY
//在此Wi-Fi鎖定模式下冀续,Wi-Fi將優(yōu)先運行以實現(xiàn)低延遲
//低延遲模式進行了優(yōu)化,以減少數(shù)據(jù)包延遲搀暑,因此沥阳,在進行權衡時,其他性能指標可能會受到影響
//
//WIFI_MODE_FULL_HIGH_PERF
//在此Wi-Fi鎖定模式下自点,Wi-Fi不會節(jié)電桐罕。這樣可以降低數(shù)據(jù)包延遲。僅當設備連接到接入點時桂敛,鎖才處于活動狀態(tài)功炮。
//即使設備屏幕關閉或獲取應用程序在后臺運行,該鎖定也處于活動狀態(tài)术唬。此模式將消耗更多功率薪伏,因此僅在需要此折衷時才應使用。
//
creatWifiLock("WifiLocKManager", WifiManager.WIFI_MODE_SCAN_ONLY);
}
public void creatWifiLock(String locakName, int lockType) {
mWifiLock = mWifiManager.createWifiLock(lockType, locakName);
}
/**
* * 創(chuàng)建一個WifiLock
* *
* * @param locakName 名稱
*
*/
public void creatWifiLock(String locakName) {
mWifiLock = mWifiManager.createWifiLock(locakName);
}
/**
* * 鎖定WifiLock
*
*/
public void acquireWifiLock() {
mWifiLock.acquire();
}
/**
* * 解鎖WifiLock
*
*/
public void releaseWifiLock() {
// 判斷時候鎖定
if (mWifiLock.isHeld()) {
mWifiLock.release();
}
}
}