1. 程式人生 > >android WiFi掃描並連線

android WiFi掃描並連線

wifi掃描並顯示

獲取列表

獲取Wifi列表並不難,網上有一個WifiAdmin的工具類,一找一大堆。但是這個工具類其中還是有很多問題的,並不建議直接使用。在使用過程中還是踩到了其中的一些坑,然後修改一下。

  • WiFi名稱SSID重複和BSSID 
    在wifiAdmin中有一個startScan的方法,是獲取當前掃描到的所有wifi,另一方法getList就是外部呼叫獲取wifi列表。 
    SSID就是我們看到的WIFI名,BSSID是在該區域網內唯一的ip。一開始我想是一BSSID做為唯一標識判斷重複,但是發現不行。因為如果你的路由器很大或者路由器下面繼續接了很多路由器,那麼你就會發現通過獲取的WifiManager.getScanResults()獲取的wifiList中有很多SSID相同,但是BSSID不同的WIFI。那麼這些WIFI到底是不是同一個呢,答案是肯定的。然後就得根據SSID進行判重。
    /**
     * 得到網路列表
     *
     * @return the wifi list all
     */
    public ArrayList<ScanResult> getWifiListAll() {
        ArrayList<ScanResult> newSr = new ArrayList<ScanResult>();
        for (ScanResult result : mAllData) {
            if (!TextUtils.isEmpty(result.SSID) && !result.capabilities.contains("[IBSS]"
) && !containName(newSr, result)) newSr.add(result); } return newSr; } /** * 判斷一個掃描結果中,是否包含了某個名稱的WIFI * * @param sr * 掃描結果 * @param scanResult * 要查詢的名稱 * * @return 返回true表示包含了該名稱的WIFI ,返回false表示不包含 */
public boolean containName(List<ScanResult> sr, ScanResult scanResult) { for (ScanResult result : sr) { if (!TextUtils.isEmpty(result.SSID) && result.SSID.equals(scanResult.SSID) && result.capabilities.equals(scanResult.capabilities)) { return true; } } return false; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • WIFI篩選 
    其實在做判重前可以先做一遍篩選,因為不是所有的WIFI都是我們想要的,我這根據頻段做了一次篩選。把startscan方法修改了一下。
    /**
     * 開始掃描
     */
    public void startScan() {
        mWifiManager.startScan();
        // 得到掃描結果
//        mWifiList = mWifiManager.getScanResults();
        m24GData.clear();
        m24GData = null;
        m24GData = new ArrayList<ScanResult>();
        m5GData.clear();
        m5GData = null;
        m5GData = new ArrayList<ScanResult>();
        mAllData.clear();
        mAllData = null;
        mAllData = new ArrayList<ScanResult>();
        try {
            List<ScanResult> list = mWifiManager.getScanResults();
            if (list != null) {
                for (ScanResult scanResult : list) {
                    int nSigLevel = WifiManager.calculateSignalLevel(
                            scanResult.level, 100);
                    int value = scanResult.frequency;
                    if (value > 2400 && value < 2500) {
                        m24GData.add(scanResult);
                    } else {
                        m5GData.add(scanResult);
                    }
                    mAllData.add(scanResult);
                }
            } else {
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 得到配置好的網路連線
        mWifiConfiguration = mWifiManager.getConfiguredNetworks();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

WIFI連線

一開始我是使用廣播來判斷是否連線成功,但要是連線成功還好說,連線不成功我我並不能拿到是哪個未連線成功。後來發現WifiAdmin中也有連線WIFI的方法,試了一下,並不好用。所以重新寫了一個連線的方法。原來的方法是直接通過WifiManager.addNetwork()時返回的一個int值返回來判斷是否連線成功,但是這個只是是新增成功,並不是連線成功。之後發現WifiManager.enableNetwork()會返回一個boolean值,天真的我以為返回true就是連線成功的意思了,但其實這個值也是不準的。看他的enableNetwork的原始碼發現有這麼一個註釋。

    /**
     * Allow a previously configured network to be associated with. If
     * <code>disableOthers</code> is true, then all other configured
     * networks are disabled, and an attempt to connect to the selected
     * network is initiated. This may result in the asynchronous delivery
     * of state change events.
     * <p>
     * <b>Note:</b> If an application's target SDK version is
     * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
     * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
     * instead be sent through another network, such as cellular data,
     * Bluetooth tethering, or Ethernet. For example, traffic will never use a
     * Wi-Fi network that does not provide Internet access (e.g. a wireless
     * printer), if another network that does offer Internet access (e.g.
     * cellular data) is available. Applications that need to ensure that their
     * network traffic uses Wi-Fi should use APIs such as
     * {@link Network#bindSocket(java.net.Socket)},
     * {@link Network#openConnection(java.net.URL)}, or
     * {@link ConnectivityManager#bindProcessToNetwork} to do so.
     *
     * @param netId the ID of the network in the list of configured networks
     * @param disableOthers if true, disable all other networks. The way to
     * select a particular network to connect to is specify {@code true}
     * for this parameter.
     * @return {@code true} if the operation succeeded
     */
    public boolean enableNetwork(int netId, boolean disableOthers) {
        final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
        if (pin) {
            NetworkRequest request = new NetworkRequest.Builder()
                    .clearCapabilities()
                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                    .build();
            NetworkPinner.pin(mContext, request);
        }

        boolean success;
        try {
            success = mService.enableNetwork(netId, disableOthers);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        if (pin && !success) {
            NetworkPinner.unpin();
        }

        return success;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

所以這個返回值的意思只是有沒有去進行連線這個操作,進行連線這個操作了,就返回true,並不是有沒有連線成功。值得提一下的是disableOthers這個引數,如果是true則會連的時候將其他的都斷開,如果是false,則不會。在使用的時候建議先將所有的斷開,這樣會比較快一點。 
在網上找了好多資料之後還是回到了使用廣播判斷WIFI是否連線成功。把連線這塊單獨提了出來做了一個類。在連線前先將需要連線的WIFI傳入,然後在連線的時候給他加一把執行緒鎖,設定一個超時時間,等待廣播結果。然後再通過介面回撥,將連線狀態和WIFI資訊一併傳出。

具體連線的程式碼就不貼了,太長了。

有幾個個問題需要特別注意一下。

我遇到一個4.2.2的系統,他會在連線的時候先將WIFI關閉,然後再開啟。這個問題困擾我很長時間,後來找到了需要提高所需連線WIFI的優先順序。

        cfg.networkId = mNetworkID;
        int newPri = wifiAdmin.getMaxPriority() + 1;
        cfg.priority = newPri;//提高優先順序

        mWifiManager.updateNetwork(cfg);//更新
        mWifiManager.saveConfiguration();//儲存
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

還有一個就是當連線一個之前連線過的,但是密碼已經修改了,需要把原來的移除掉,然後再新增上,不然在設定頁面進行忘記密碼的時候會需要忘記好幾次才能完全忘記。

    /**
     * Remove exit config.
     * 移除已經連線過的
     *
     * @param ssid
     *         the ssid
     */
    public void removeExitConfig(String ssid) {
        WifiConfiguration exsits = isExsits(ssid);
        if (exsits != null) {//如果已經連線過則刪除
            mWifiManager.removeNetwork(exsits.networkId);
        }

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
/**
     * Is exsits wifi configuration.
     * 判斷是否已經連線過
     *
     * @param SSID
     *         the ssid
     *
     * @return the wifi configuration
     */
    public WifiConfiguration isExsits(String SSID) {
        List<WifiConfiguration> existingConfigs = mWifiManager.getConfiguredNetworks();
        for (WifiConfiguration existingConfig : existingConfigs) {
            if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
                return existingConfig;
            }
        }
        return null;
    }