Android Wifi 開(kāi)發(fā)相關(guān)

眼看自己來(lái)這個(gè)公司的第一個(gè)項(xiàng)目,也是公司的核心項(xiàng)目即將上線了,細(xì)數(shù)一番,已有半年之久,中間也做了一些小項(xiàng)目,忍不住驚嘆了一下,這么久了居然沒(méi)有做下筆記,真是罪過(guò)罪過(guò)。記得學(xué)習(xí)android之時(shí)就喜歡記下開(kāi)發(fā)知識(shí)點(diǎn),開(kāi)發(fā)技巧。在我看來(lái),總結(jié)可以使自己穩(wěn)步進(jìn)步。趁項(xiàng)目稍微空余時(shí)期,總結(jié)一下,涉及到WIFI開(kāi)發(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)是由一系列的整形常量來(lái)表示的)


image
2. ScanResult
主要用來(lái)描述已經(jīng)檢測(cè)出的接入點(diǎn),包括接入點(diǎn)的地址,接入點(diǎn)的名稱,身份認(rèn)證,頻率,信號(hào)強(qiáng)度等信息。其實(shí)就是通過(guò)wifi 硬件的掃描來(lái)獲取一些周邊的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èn)的無(wú)線網(wǎng)絡(luò)應(yīng)用模式)的應(yīng)用,一個(gè)無(wú)線網(wǎng)絡(luò)至少由一個(gè)連接到有線網(wǎng)絡(luò)的AP和若干無(wú)線工作站組成,這種配置稱為一個(gè)基本服務(wù)裝置。一群計(jì)算機(jī)設(shè)定相同的 BSS名稱,即可自成一個(gè)group,而此BSS名稱,即所謂BSSID。通常,手機(jī)WLAN中,bssid其實(shí)就是無(wú)線路由的MAC地址。

networkid:網(wǎng)絡(luò)ID。

PreSharedKey:無(wú)線網(wǎng)絡(luò)的安全認(rèn)證模式。

SSID:SSID(Service SetIdentif)用于標(biāo)識(shí)無(wú)線局域網(wǎng),SSID不同的無(wú)線網(wǎng)絡(luò)是無(wú)法進(jìn)行互訪的。

4. WifiInfo
wifi無(wú)線連接的描述,包括(接入點(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)沒(méi)什么卵用- -)
getMacAddress() 獲得Mac 地址
getRssi() 獲得802.11n 網(wǎng)絡(luò)的信號(hào)

在AndroidManifest.xml進(jìn)行對(duì)WIFI操作的權(quán)限設(shè)置

<!-- 以下是使用wifi訪問(wèn)網(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開(kāi)發(fā) 我想第一點(diǎn)首先是如何打開(kāi)wifi開(kāi)關(guān)

打開(kāi)之前先獲取WifiManager 對(duì)象,通過(guò)該對(duì)象的isWifiEnabled():boolean 方法來(lái)獲取當(dāng)前wifi的開(kāi)啟情況,如果未打開(kāi),則執(zhí)行打開(kāi)wifi開(kāi)關(guān)操作

WifiManager  mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (!mWifiManager.isWifiEnabled()) {//wifi未打開(kāi) 執(zhí)行打開(kāi)操作
    mWifiManager.setWifiEnabled(true);//同樣的執(zhí)行關(guān)閉操作的話: mWifiManager.setWifiEnabled(false);
}
2. WIFI打開(kāi)之后自然是執(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ù)需求情況 自行過(guò)濾
 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的問(wèn)題,因此每次去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沒(méi)有密碼 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] = "";//連接無(wú)密碼熱點(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ù)來(lái)判別是否連接成功
    *這也是我在項(xiàng)目中碰到的一個(gè)難題
    */
   
項(xiàng)目中涉及到wifi切換連接,這個(gè)時(shí)候就需要監(jiān)聽(tīng)熱點(diǎn)切換情況,這是個(gè)難點(diǎn)。不同設(shè)備的熱點(diǎn)連接速度也不一致,我的做法是啟動(dòng)一個(gè)定時(shí)任務(wù),當(dāng)wifi進(jìn)行切換時(shí)先保存oldCurrentSSID,gonaLinkSSID來(lái)保存目的連接SSID,然后定時(shí)的去讀取當(dāng)前連接中的ssid:mWifiInfo.getSSID(),來(lái)實(shí)時(shí)的監(jiān)聽(tīng)當(dāng)前熱點(diǎn)情況,如果當(dāng)前熱點(diǎn)與oldCurrentSSID不等,并且等于gonaLinkSSID,即代表熱點(diǎn)切換成功。這邊需要考慮的是這個(gè)定時(shí)的長(zhǎng)度,因?yàn)閣ifi沒(méi)有正在連接的狀態(tài),所以這邊無(wú)法準(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ā)出一條廣播)來(lái)得到最準(zhǔn)確的值。

</br>

6. 斷開(kāi)指定連接

 // 斷開(kāi)指定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", "斷開(kāi)連接 id" + linkingID);
    }
    
 //有些情況下我們可能并不方便拿到那個(gè)id,這個(gè)時(shí)候可以投機(jī)取巧的地方是隨便連接一個(gè)不能連接成功的ssid,當(dāng)ssid切換的時(shí)候 wifi會(huì)先自動(dòng)斷開(kāi)當(dāng)前連接的熱點(diǎn)才去連接目標(biāo)ssid    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容