關(guān)于WifiManager開發(fā)遇到的幾個(gè)坑

需求:本人搞物聯(lián)網(wǎng),wifi需要上網(wǎng),前提需要先讓wifi模組連接上路由器,存在wifi模組配網(wǎng)的過程。

有兩種配網(wǎng)模式,

  • SmartLink,一種使用UDP廣播技術(shù)實(shí)現(xiàn)的一種快速配網(wǎng)的技術(shù),改技術(shù)有一個(gè)致命的缺陷,當(dāng)路由不支持UPD廣播,或者被封禁的時(shí)候,改技術(shù)無法使用了。

  • SoftAP,這種比較傳統(tǒng)的方式,先讓手機(jī)與wifi模組建立的熱點(diǎn)進(jìn)行連接,將需要連接的wifi路由 ssid與password告知wifi模組后,讓wifi模組去連接。兼容性很好,貴在比較復(fù)雜,操作步驟多。

對于Android系統(tǒng)來說,因?yàn)榭梢詫ifi進(jìn)行操作,可以做到與SmartLink一樣的快捷,更多的交給后臺處理完成配網(wǎng);將使用到WifiManager這個(gè)系統(tǒng)類;

坑一:WifiManager獲取時(shí)產(chǎn)生內(nèi)存泄露

引用前輩的帖子, http://www.itdecent.cn/p/5d96983fc6db

坑二:addNetwork返回-1

相信很多人在這塊開發(fā)的時(shí)候都不會自己一個(gè)一個(gè)字母的敲出來,網(wǎng)上copy一下完成了。

基本上網(wǎng)上的代碼就這么一寫,注意紅框中的兩個(gè)方法;

你會發(fā)現(xiàn)在很多請情況下addNetword都是返回-1;這將會使enableNetword 無法連接到指定的wifi中;

Google API

官方APP描述,新網(wǎng)絡(luò)描述添加到已配置網(wǎng)絡(luò)集。也就是說這個(gè)方法用于新的,未連接過的wifi;適當(dāng)換成

//判斷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;
    }

坑三:掃描獲取手機(jī)附近wifi列表返回 size=0

    /**
     * 獲取wifi列表
     *
     * @return
     */
    private List<ScanResult> getWifiList() {
        // 開始掃描
        wifiManager.startScan();
        // 得到掃描結(jié)果
        return wifiManager.getScanResults();
    }

坑四:連接沒有密碼的AP熱點(diǎn)

把taget版本支持到28之后,發(fā)現(xiàn)連接AP熱點(diǎn)怎么也連不上了,經(jīng)過一段時(shí)間的測試,發(fā)現(xiàn)AP熱點(diǎn)沒有密碼的時(shí)候, 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開關(guān)把,完美解決;

(目前miui 系統(tǒng),還是無法正常連接到指定的wifi,打印log顯示已經(jīng)連接了,實(shí)際手機(jī)沒有切換過去,不知道什么問題,有遇到這樣問題的,希望可以指導(dǎo)下我;)引用評論3樓的方法,在連接之前先disconnect,再連接,解決;感謝?。?!

2019-11-04 繼續(xù)補(bǔ)充

坑五 關(guān)于 MIUI、華為 disconnect之后 積極連接其他wifi問題的處理

小米與華為手機(jī)斷開連接后,會非??焖俚倪B接曾經(jīng)連接過的WIFI,這時(shí) enableNetwork 方法壓根搶不過系統(tǒng),導(dǎo)致連接AP 熱點(diǎn)失敗。
引用前輩一篇文章,代碼寫得比較全了,里面注釋也提到了這個(gè)問題 。
https://juejin.im/post/5b18c3d1f265da6e3c6b93da

說下我解決這個(gè)問題的過程,網(wǎng)上其實(shí)有一些極端的方法可以解決這個(gè)問題。
1、WiFiManager.disableNetwork()
使用 disableNetwork 方法,該方法是講已經(jīng)保存的wifi進(jìn)行禁用,禁用之后,系統(tǒng)就不會自動的去連接這些連接過的WIFI,解決這個(gè)問題(華為測試過之后);
(小米去測試的時(shí)候就惡心了,MIUI系統(tǒng)每次操作WIFI都會提示用戶,是否允許操作wifi,也就是說你保存了100個(gè)wifi的配置你得點(diǎn)100次允許,了勒個(gè)去?。。。?br> 2、WifiManager.WifiLock
沒法子,又得去爬谷歌的API文檔了,英語不好,折磨。。。


image.png

主要使用以上三個(gè)方法,給WIFI加鎖。

public class WifiLocKManager {
    // 定義WifiManager對象
    private WifiManager mWifiManager;
    // 定義一個(gè)WifiLock
    private WifiManager.WifiLock mWifiLock;

    private Context context;

    public WifiLocKManager(Context context) {
        // 取得WifiManager對象
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        //第一種方式
        creatWifiLock("WifiLocKManager");
        //第二種方式
        //解析一下三個(gè)常量
        //WIFI_MODE_SCAN_ONLY    在此Wi-Fi鎖定模式下,Wi-Fi將保持活動狀態(tài),但是唯一受支持的操作是啟動掃描以及隨后報(bào)告掃描結(jié)果。
        // 不會嘗試自動連接到記住的訪問點(diǎn),也不會自動執(zhí)行定期掃描以查找記住的訪問點(diǎn)。在這種模式下,應(yīng)用程序必須明確請求掃描。
        //····································································
        //WIFI_MODE_FULL_LOW_LATENCY
        //在此Wi-Fi鎖定模式下,Wi-Fi將優(yōu)先運(yùn)行以實(shí)現(xiàn)低延遲
        //低延遲模式進(jìn)行了優(yōu)化,以減少數(shù)據(jù)包延遲,因此,在進(jìn)行權(quán)衡時(shí),其他性能指標(biāo)可能會受到影響
        //
        //WIFI_MODE_FULL_HIGH_PERF
        //在此Wi-Fi鎖定模式下,Wi-Fi不會節(jié)電。這樣可以降低數(shù)據(jù)包延遲。僅當(dāng)設(shè)備連接到接入點(diǎn)時(shí),鎖才處于活動狀態(tài)。
        //即使設(shè)備屏幕關(guān)閉或獲取應(yīng)用程序在后臺運(yùn)行,該鎖定也處于活動狀態(tài)。此模式將消耗更多功率,因此僅在需要此折衷時(shí)才應(yīng)使用。
        //
        creatWifiLock("WifiLocKManager", WifiManager.WIFI_MODE_SCAN_ONLY);
    }

    public void creatWifiLock(String locakName, int lockType) {
        mWifiLock = mWifiManager.createWifiLock(lockType, locakName);
    }

    /**
     *  * 創(chuàng)建一個(gè)WifiLock
     *  *
     *  * @param locakName 名稱
     *  
     */
    public void creatWifiLock(String locakName) {
        mWifiLock = mWifiManager.createWifiLock(locakName);
    }

    /**
     *  * 鎖定WifiLock
     *  
     */
    public void acquireWifiLock() {
        mWifiLock.acquire();
    }

    /**
     *  * 解鎖WifiLock
     *  
     */
    public void releaseWifiLock() {
// 判斷時(shí)候鎖定
        if (mWifiLock.isHeld()) {
            mWifiLock.release();
        }
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容