天天看點

Android/安卓開發之WIFI的基本應用

本文沒有涉及到連接配接WIFI之後進行通訊,若有這方面的想法(例如兩個用戶端連接配接至同一WIFI後進行通訊),請關注後續文章一起讨論。

其實關于WIFI的開發的文章也非常的多,但是大部分隻是簡單的例子,不夠全面,我這裡是想寫一個比較完整的WIFI應用,主要功能:

1.能夠打開/關閉WIFI

2.能夠掃面wifi并擷取掃描結果

3.能夠連接配接wifi,無論是什麼加密方式

4.能夠監聽連接配接狀态,如正在連接配接、正在擷取ip、密碼錯誤等

5.能夠鎖定wifi

6.能擷取wifi的加密方式

7.開啟熱點

8.等等,大部分wifi操作常用的功能...

至于開發中用的幾個相關類我就不做過多介紹了,網上比比皆是,還不了解的可以先看一下其他部落格的介紹或者官方文檔。

我盡量在代碼中增加了一些注釋,還是那句話:我還是個安卓小白,錯誤在所難免,如果有錯誤,希望大家多多指點。

一般使用WIFI流程:

1.打開wifi

1.1 狀态監聽

2.掃描wifi

3.連接配接wifi

4.關閉wifi

其中連接配接需要分幾種情況:

1.如果是之前已經儲存,直接連接配接

2.如果沒有儲存,必須先進行配置,再連接配接

2.1配置需要區分三種加密方式:無密碼、WEP、WPA

3.WPS連接配接

那麼就來打造一個簡單demo,按照以上的步驟來。

開發流程

我們為了以後使用友善,直接編寫一個wifi管理類,然後在activity直接調用對應方法就行了。下面着手進行這個類的編寫:

0.在開始開發之前我們需要先配置相應的權限,如果是Android N以上級的動态申請位置權限哦

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <!-- 在android N 以上 需要添加位置權限 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
           

然後先看看我們需要準備什麼全局變量

private WifiManager mWifiManager;//wifi管理器
    private List<ScanResult> mScanResults;//掃描結果
    private Context mContext;
    private WifiStateReceiver mReceiver;//廣播接收器
    private WifiStateChangeListener mWifiStateChangeListener;//
    private WifiManager.WifiLock mWifiLock;//WIFI鎖
    private static WiFiAdmin mWifiAdmin;//單利模式,
           

1.第一步,初始化wifi管理器并打開wifi

初始化

/***
     * 構造方法  - - 由于使用單例,是以設為私有
     * @param context
     */
    private WiFiAdmin(Context context) {
        mContext = context;
        //如果使用activity的context則不能通路存儲空間,在版本大于Android N時,是以使用全局的Context
        mWifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        mWifiLock = mWifiManager.createWifiLock("mlock");
    }
           

打開wifi

public void openWifi() {
        if (!mWifiManager.isWifiEnabled()) {
            mWifiManager.setWifiEnabled(true);
        }
    }
           

2.注冊廣播,接收wifi的一些狀态,例如正在連接配接、正在擷取ip位址、斷開連接配接等

private void registerWifiRecv() {
        //注冊廣播
        mReceiver = new WifiStateReceiver();
        IntentFilter mFilter = new IntentFilter();
        mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); //信号強度變化
        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); //網絡狀态變化
        mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); //wifi狀态,是否連上,密碼
        mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); //是不是正在獲得IP位址
        mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
        mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        mContext.registerReceiver(mReceiver, mFilter);
        isRegisterRecv = true;
    }
           

3.既然注冊了廣播,那麼我們肯定要處理對應結果

class WifiStateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (!isRegisterRecv) return;//沒注冊監聽就沒必要執行之後的邏輯
            String action = intent.getAction();
            switch (action) {
                case WifiManager.RSSI_CHANGED_ACTION:
                    //信号強度變化
                    mWifiStateChangeListener.onSignalStrengthChanged(getStrength(context));
                    break;
                case WifiManager.NETWORK_STATE_CHANGED_ACTION:
                    NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
                    if (info.getDetailedState().equals(NetworkInfo.DetailedState.DISCONNECTED)) {
                        //wifi已斷開
                        mWifiStateChangeListener.onWifiDisconnect();
                    } else if (info.getDetailedState().equals(NetworkInfo.DetailedState.CONNECTING)) {
                        //正在連接配接...
                        mWifiStateChangeListener.onWifiConnecting();
                    } else if (info.getDetailedState().equals(NetworkInfo.DetailedState.CONNECTED)) {
                        //連接配接到網絡
                        mWifiStateChangeListener.onWifiConnected();
                    }else if(info.getDetailedState().equals(NetworkInfo.DetailedState.OBTAINING_IPADDR)){
                        //正在擷取IP位址
                        mWifiStateChangeListener.onWifiGettingIP();
                    }else if(info.getDetailedState().equals(NetworkInfo.DetailedState.FAILED)){
                        //連接配接失敗
                    }

                    break;
                case WifiManager.WIFI_STATE_CHANGED_ACTION:
                    int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
                    switch (wifiState) {
                        case WifiManager.WIFI_STATE_ENABLING:
                            //wifi正在啟用
                            mWifiStateChangeListener.onWifiEnabling();
                            break;
                        case WifiManager.WIFI_STATE_ENABLED:
                            //Wifi已啟用
                            mWifiStateChangeListener.onWifiEnable();
                            break;
                    }
                    break;
                case WifiManager.SUPPLICANT_STATE_CHANGED_ACTION:
                    int error = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -100);
                    LogUtil.log("密碼認證錯誤:"+error+"\n");
                    if (error==WifiManager.ERROR_AUTHENTICATING){
                        //wifi密碼認證錯誤!
                        mWifiStateChangeListener.onPasswordError();
                    }
                    break;
                case WifiManager.NETWORK_IDS_CHANGED_ACTION:
                    //已經配置的網絡的ID可能發生變化時
                    mWifiStateChangeListener.onWifiIDChange();
                    break;
                case ConnectivityManager.CONNECTIVITY_ACTION:
                    //連接配接狀态發生變化,暫時沒用到
                    int type = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,0);
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 計算信号強度
     *
     * @param context 含有WIFI資訊的資源對象
     * @return 信号強度
     */
    private int getStrength(Context context) {
        WifiInfo info = getConnectInfo();
        if (info.getBSSID() != null) {
            int strength = WifiManager.calculateSignalLevel(info.getRssi(), 5);
            // 連結速度
//			int speed = info.getLinkSpeed();
//			// 連結速度機關
//			String units = WifiInfo.LINK_SPEED_UNITS;
//			// Wifi源名稱
//			String ssid = info.getSSID();
            return strength;
        }
        return 0;
    }
           

4.然後發起掃描并擷取掃描結果

/**
     * 啟動掃描,掃描前應使用 {@link #getWifiState()}判斷WIFI是否可用
     * 或者在回調函數 mWifiStateChangeListener.onWifiEnable() 調用
     */
    public void startWifiScan() {
        mWifiManager.startScan();
        mScanResults = mWifiManager.getScanResults();
    }
           

5.擷取到掃描結果之後,我們就可以發起連接配接了。對于之前已經連接配接過的wifi,可以直接這樣:

public boolean connectWifi(int netId) {
        return mWifiManager.enableNetwork(netId, true);
    }
           

那麼netid怎麼來的?這就需要以下這些操作,首先要擷取已經配置過(就是之前連接配接過的)的wifi

public WifiInfo getConnectInfo() {
        return mWifiManager.getConnectionInfo();
    }
           

使用以下方法擷取netid,如果傳回-1,證明沒有配置,需要配置才能發起連接配接請求。

public int isWifiConfig(String ssid) {
        List<WifiConfiguration> lists = getConfigWifiList();
        for (WifiConfiguration c : lists) {
            if (c.SSID.equals("\"" + ssid + "\"")) {
                return c.networkId;
            }
        }
        return -1;
    }
           

而如果是連接配接新的wifi(上面的方法傳回-1)需要先配置對應的參數,例如密碼之類的才能發起連接配接

public int configWifi(String ssid, String pwd,int security) {
        int result = -1;
        for (ScanResult s : mScanResults) {
            if (s.SSID.equals(ssid)) {
                WifiConfiguration config = new WifiConfiguration();
                config.SSID = "\"" + ssid + "\"";
                config.hiddenSSID = false;
                config.status = WifiConfiguration.Status.ENABLED;
                switch (security){
                    case SECURITY_NONE:
                        config.wepKeys[0] ="\""+pwd+"\"";
                        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                        config.wepTxKeyIndex = 0;
                        break;
                    case SECURITY_WEP:
                        config.wepKeys[0]= "\""+pwd+"\"";
                        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                        config.wepTxKeyIndex = 0;
                        break;
                    case SECURITY_WPA:
                    case SECURITY_WPA_PSK:
                        config.preSharedKey = "\"" + pwd + "\"";
                        break;
                    default:
                        break;
                }
                result = mWifiManager.addNetwork(config);
                break;
            }
        }
        return result;
    }
           

配置完成再次調用擷取netid的方法就可以擷取netid了 

6.經過步驟5,我們已經能連接配接上wifi,接下來就可以退出程式,愉快的上網了。當然,如果不需要wifi了,别忘了關閉哦~

public void closeWifi() {
        if (mWifiManager.isWifiEnabled()) {
            mWifiManager.setWifiEnabled(false);
        }
    }
           

上面是簡化後的步驟,像在配置時,還需要判斷有沒有加密,加密方式是什麼,怎麼擷取加密方式等都省略了。全部了解請看下方全部代碼哦~

下面有關于wifi的更多操作,也有要共享wifi的法等。

總體就是這種流程,按照這個流程來調用對應的方法就差不多了。記得根據步驟來閱讀,才不會覺得混亂。下面是wifi管理類的全部代碼,我整合大部分需要用到的功能:

package cn.small_qi.wificonn;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Created by small_qi on 2017/7/21.
 */
public class WiFiAdmin {
    private WifiManager mWifiManager;
    private List<ScanResult> mScanResults;
    private Context mContext;
    private WifiStateReceiver mReceiver;
    private WifiStateChangeListener mWifiStateChangeListener;
    private WifiManager.WifiLock mWifiLock;
    private static WiFiAdmin mWifiAdmin;
    private boolean isRegisterRecv;
    private boolean isWifiLock;

    public static final int SECURITY_WEP = 3;//WEP
    public static final int SECURITY_WPA = 2;//WPA/WPA2
    public static final int SECURITY_WPA_PSK = 1;//WPA-PSK/WPA2-PSK
    public static final int SECURITY_NONE = 0;//沒有密碼
    public static final int ORDER_SMART_SORT = 0;//智能排序,
    public static final int ORDER_SIGNAL_LEVEL_SORT = 1;//信号強度排序

    /***
     * 構造方法  - - 由于使用單例,是以設為私有
     * @param context
     */
    private WiFiAdmin(Context context) {
        mContext = context;
        //如果使用activity的context則不能通路存儲空間,在版本大于Android N時,是以使用全局的Context
        mWifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        mWifiLock = mWifiManager.createWifiLock("mlock");
    }

    /**
     * 對外面公開的擷取執行個體的方法
     *
     * @param context
     * @return 建立的
     */
    public static WiFiAdmin getInstance(Context context) {
        if (mWifiAdmin == null) {
            mWifiAdmin = new WiFiAdmin(context);
        }
        return mWifiAdmin;
    }

    /**
     * 設定網絡狀态監聽
     * 如果設定了監聽,一定要在調用的Activity/Fragment
     * 的生命周期結束時調用{@link #removeWifiStateChangeListener()}
     * 避免記憶體洩漏
     */
    public void addWifiStateChangeListener(WifiStateChangeListener wscListener) {
        if (isRegisterRecv) return;
        registerWifiRecv();
        this.mWifiStateChangeListener = wscListener;
    }

    private void registerWifiRecv() {
        //注冊廣播
        mReceiver = new WifiStateReceiver();
        IntentFilter mFilter = new IntentFilter();
        mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); //信号強度變化
        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); //網絡狀态變化
        mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); //wifi狀态,是否連上,密碼
        mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); //是不是正在獲得IP位址
        mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
        mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        mContext.registerReceiver(mReceiver, mFilter);
        isRegisterRecv = true;
    }

    public void removeWifiStateChangeListener() {
        if (!isRegisterRecv) return;
        isRegisterRecv = false;
        mContext.unregisterReceiver(mReceiver);
    }


    public void openWifi() {
        if (!mWifiManager.isWifiEnabled()) {
            mWifiManager.setWifiEnabled(true);
        }
    }

    public void closeWifi() {
        if (mWifiManager.isWifiEnabled()) {
            mWifiManager.setWifiEnabled(false);
        }
    }

    public boolean lockWifi() {
        if (mWifiLock == null) {
            return false;
        }
        mWifiLock.acquire();
        isWifiLock = true;
        return true;
    }

    public boolean unLockWifi() {
        if (mWifiLock == null) {
            return false;
        }
        mWifiLock.release();
        isWifiLock = false;
        return true;
    }

    public boolean isWifiLock() {
        return isWifiLock;
    }

    /**
     * 擷取網卡狀态
     *
     * @return
     */
    public int getWifiState() {
        /**
         * WIFI網卡的狀态是由一系列的整形常量來表示的。
           1.WIFI_STATE_DISABLED : WIFI網卡不可用(1)
           2.WIFI_STATE_DISABLING : WIFI網卡正在關閉(0)
           3.WIFI_STATE_ENABLED : WIFI網卡可用(3)
           4.WIFI_STATE_ENABLING : WIFI網正在打開(2) (WIFI啟動需要一段時間)
           5.WIFI_STATE_UNKNOWN  : 未知網卡狀态
         */
        if (mWifiManager.isWifiEnabled()) {
            return mWifiManager.getWifiState();
        }
        return -1;
    }

    /**
     * 啟動掃描,掃描前應使用 {@link #getWifiState()}判斷WIFI是否可用
     * 或者在回調函數 mWifiStateChangeListener.onWifiEnable() 調用
     */
    public void startWifiScan() {
        mWifiManager.startScan();
        mScanResults = mWifiManager.getScanResults();
    }


    /**
     * 擷取排序後的掃描結果
     *
     * @param order 排序方式
     *              1.隻按信号強度排序
     *              2.已經儲存的在前面,其他按強度排序
     */
    public List<ScanResult> getOrderScanResults(int order) {
        List<ScanResult> sortResult = mScanResults;
        if (order == ORDER_SIGNAL_LEVEL_SORT) {
            levelSort(sortResult);
        } else if (order == ORDER_SMART_SORT) {
            smartSort(sortResult);
        }
        return null;
    }

    private void levelSort(List<ScanResult> sortResult) {
        Collections.sort(sortResult, new Comparator<ScanResult>() {
            @Override
            public int compare(ScanResult o1, ScanResult o2) {
                return o1.level - o2.level;
            }
        });
    }

    private void smartSort(List<ScanResult> sortResult) {
        Collections.sort(sortResult, new Comparator<ScanResult>() {
            @Override
            public int compare(ScanResult o1, ScanResult o2) {
                if (isWifiConfig(o1.SSID) > 0 && isWifiConfig(o2.SSID) > 0) {
                    return o1.level - o2.level;
                } else if (isWifiConfig(o1.SSID) > 0 || isWifiConfig(o2.SSID) > 0) {
                    return isWifiConfig(o1.SSID) - isWifiConfig(o2.SSID);
                } else {
                    return o1.level - o2.level;
                }
            }
        });
    }

    /**
     * 擷取掃描結果
     */
    public List<ScanResult> getScanResults() {
        return mScanResults;
    }

    /**
     * 擷取已經儲存的wifi清單
     */
    public List<WifiConfiguration> getConfigWifiList() {
        List<WifiConfiguration> configurations = mWifiManager.getConfiguredNetworks();
        return configurations;
    }

    /**
     * 判斷該wifi是否已經儲存
     *
     * @return 傳回-1表示沒儲存,已經儲存傳回網絡id
     */
    public int isWifiConfig(String ssid) {
        List<WifiConfiguration> lists = getConfigWifiList();
        for (WifiConfiguration c : lists) {
            if (c.SSID.equals("\"" + ssid + "\"")) {
                return c.networkId;
            }
        }
        return -1;
    }

    /**
     * 配置沒有儲存的wifi
     * 一般隻要配置一下幾個屬性就可以了,其他使用其,預設值
     * @param scanResult
     * @param pwd
     * @return 儲存成功則傳回該Wifi的網絡id,否則-1
     */
    public int configWifi(ScanResult scanResult, String pwd,int security) {
        return configWifi(scanResult.SSID,pwd,security);

    }

    /**
     * 配置方法重載
     */
    public int configWifi(String ssid, String pwd,int security) {
        int result = -1;
        for (ScanResult s : mScanResults) {
            if (s.SSID.equals(ssid)) {
                WifiConfiguration config = new WifiConfiguration();
                config.SSID = "\"" + ssid + "\"";
                config.hiddenSSID = false;
                config.status = WifiConfiguration.Status.ENABLED;
                switch (security){
                    case SECURITY_NONE:
                        config.wepKeys[0] ="\""+pwd+"\"";
                        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                        config.wepTxKeyIndex = 0;
                        break;
                    case SECURITY_WEP:
                        config.wepKeys[0]= "\""+pwd+"\"";
                        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                        config.wepTxKeyIndex = 0;
                        break;
                    case SECURITY_WPA:
                    case SECURITY_WPA_PSK:
                        config.preSharedKey = "\"" + pwd + "\"";
                        break;
                    default:
                        break;
                }
                result = mWifiManager.addNetwork(config);
                break;
            }
        }
        return result;
    }

    /**
     * 配置方法重載,用于更複雜的配置
     */
    public int configWifi(WifiConfiguration config) {
        return mWifiManager.addNetwork(config);
    }

    /**
     * 擷取加秘方式
     */
    public int getSecurity(ScanResult scanResult) {
        return getSecurity(scanResult.capabilities);
    }

    /**
     * 擷取加秘方式
     *
     * @param capabilities
     * @return 加密類型, 具體類型請檢視: {@link #SECURITY_NONE}{@link #SECURITY_WEP}{@link #SECURITY_WPA}{@link #SECURITY_WPA_PSK}
     */
    public int getSecurity(String capabilities) {
        if (capabilities.contains("WEP")) {
            return SECURITY_WEP;
        } else if (capabilities.contains("WPA")) {
            if (capabilities.contains("PSK"))
                return SECURITY_WPA_PSK;
            return SECURITY_WPA;
        } else {
            return SECURITY_NONE;
        }
    }

    /**
     * 删除/忘記一個wifi(也就是通常的不儲存)
     *
     * @param ssid 要忘記網絡名成
     * @return 執行結果
     */
    public boolean forgetWifi(String ssid) {
        for (WifiConfiguration c : getConfigWifiList()) {
            if (c.SSID.equals("\"" + ssid + "\"")) {
                return mWifiManager.removeNetwork(c.networkId);
            }
        }
        return false;
    }

    /**
     * 斷開連接配接
     * @return
     */
    public boolean disconnectWifi(){
        return mWifiManager.disableNetwork(getConnectInfo().getNetworkId());
       // mWifiManager.disconnect();//斷流
    }

    /**
     * 連接配接wifi
     *
     * @param netId wifi網絡id
     * @return 連接配接結果
     */
    public boolean connectWifi(int netId) {
        return mWifiManager.enableNetwork(netId, true);
    }

    /**
     * 擷取已經連接配接的WIFI資訊
     */
    public WifiInfo getConnectInfo() {
        return mWifiManager.getConnectionInfo();
    }

    /**
     * IP 位址轉換
     *
     * @param ip 轉換前的IP
     * @return 轉換後的IP
     */
    public static String parseIPAddressToString(int ip) {
        return ((ip & 0xff) + "." + (ip >> 8 & 0xff) + "." + (ip >> 16 & 0xff) + "." + (ip >> 24 & 0xff));
    }

    /**
     * 廣播監聽内部類
     */
    class WifiStateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (!isRegisterRecv) return;//沒注冊監聽就沒必要執行之後的邏輯
            String action = intent.getAction();
            switch (action) {
                case WifiManager.RSSI_CHANGED_ACTION:
                    //信号強度變化
                    mWifiStateChangeListener.onSignalStrengthChanged(getStrength(context));
                    break;
                case WifiManager.NETWORK_STATE_CHANGED_ACTION:
                    NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
                    if (info.getState().equals(NetworkInfo.State.DISCONNECTED)) {
                        //wifi已斷開
                        mWifiStateChangeListener.onWifiDisconnect();
                    } else if (info.getState().equals(NetworkInfo.State.CONNECTING)) {
                        //正在連接配接...
                        mWifiStateChangeListener.onWifiConnecting();
                    } else if (info.getState().equals(NetworkInfo.State.CONNECTED)) {
                        //連接配接到網絡
                        mWifiStateChangeListener.onWifiConnected();
                    }else if(info.getDetailedState().equals(NetworkInfo.DetailedState.OBTAINING_IPADDR)){
                        //正在擷取IP位址
                        mWifiStateChangeListener.onWifiGettingIP();
                    }

                    break;
                case WifiManager.WIFI_STATE_CHANGED_ACTION:
                    int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
                    switch (wifiState) {
                        case WifiManager.WIFI_STATE_ENABLING:
                            //wifi正在啟用
                            mWifiStateChangeListener.onWifiEnabling();
                            break;
                        case WifiManager.WIFI_STATE_ENABLED:
                            //Wifi已啟用
                            mWifiStateChangeListener.onWifiEnable();
                            break;
                    }
                    break;
                case WifiManager.SUPPLICANT_STATE_CHANGED_ACTION:
                    int error = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0);
                    switch (error) {
                        case WifiManager.ERROR_AUTHENTICATING:
                            //wifi密碼認證錯誤!
                            mWifiStateChangeListener.onPasswordError();
                            break;
                        default:
                            break;
                    }
                    break;
                case WifiManager.NETWORK_IDS_CHANGED_ACTION:
                    //已經配置的網絡的ID可能發生變化時
                    mWifiStateChangeListener.onWifiIDChange();
                    break;
                case ConnectivityManager.CONNECTIVITY_ACTION:
                    //連接配接狀态發生變化,暫時沒用到
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 計算信号強度
     *
     * @param context 含有WIFI資訊的資源對象
     * @return 信号強度
     */
    private int getStrength(Context context) {
        WifiInfo info = getConnectInfo();
        if (info.getBSSID() != null) {
            int strength = WifiManager.calculateSignalLevel(info.getRssi(), 5);
            // 連結速度
//			int speed = info.getLinkSpeed();
//			// 連結速度機關
//			String units = WifiInfo.LINK_SPEED_UNITS;
//			// Wifi源名稱
//			String ssid = info.getSSID();
            return strength;
        }
        return 0;
    }

    /**
     * WIFI狀态變化回調接口
     */
    public interface WifiStateChangeListener {
        //void onRssiChanged();
        //void onNetWorkStateChanged();
        //void onWifiStateChanged();
        //void onSupplicantStateChanged();
        // void NetWorkIDSChange();
        void onSignalStrengthChanged(int level);

        void onWifiConnecting();

        void onWifiGettingIP();

        void onWifiConnected();

        void onWifiDisconnect();

        void onWifiEnabling();

        void onWifiEnable();

        void onPasswordError();

        void onWifiIDChange();
        //void onWifiLock(int isLock);

    }


    //-------------------------------以下部分為開啟熱點-------------------------------------

    /**
     * 建立熱點
     *
     * @param mSSID   熱點名稱
     * @param mPasswd 熱點密碼
     * @param isOpen  是否是開放熱點
     */
    public void startWifiAp(String mSSID, String mPasswd, boolean isOpen) {
        Method method1 = null;
        try {
            method1 = mWifiManager.getClass().getMethod("setWifiApEnabled",
                    WifiConfiguration.class, boolean.class);
            WifiConfiguration netConfig = new WifiConfiguration();

            netConfig.SSID = mSSID;
            netConfig.preSharedKey = mPasswd;
            netConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            netConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
            netConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
            if (isOpen) {
                netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            } else {
                netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            }
            netConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
            netConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            netConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            netConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            method1.invoke(mWifiManager, netConfig, true);

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 擷取熱點名
     **/
    public String getApSSID() {
        try {
            Method localMethod = this.mWifiManager.getClass().getDeclaredMethod("getWifiApConfiguration", new Class[0]);
            if (localMethod == null) return null;
            Object localObject1 = localMethod.invoke(this.mWifiManager, new Object[0]);
            if (localObject1 == null) return null;
            WifiConfiguration localWifiConfiguration = (WifiConfiguration) localObject1;
            if (localWifiConfiguration.SSID != null) return localWifiConfiguration.SSID;
            Field localField1 = WifiConfiguration.class.getDeclaredField("mWifiApProfile");
            if (localField1 == null) return null;
            localField1.setAccessible(true);
            Object localObject2 = localField1.get(localWifiConfiguration);
            localField1.setAccessible(false);
            if (localObject2 == null) return null;
            Field localField2 = localObject2.getClass().getDeclaredField("SSID");
            localField2.setAccessible(true);
            Object localObject3 = localField2.get(localObject2);
            if (localObject3 == null) return null;
            localField2.setAccessible(false);
            String str = (String) localObject3;
            return str;
        } catch (Exception localException) {
        }
        return null;
    }


    /**
     * 檢查是否開啟Wifi熱點
     *
     * @return
     */
    public boolean isWifiApEnabled() {
        try {
            Method method = mWifiManager.getClass().getMethod("isWifiApEnabled");
            method.setAccessible(true);
            return (boolean) method.invoke(mWifiManager);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 關閉熱點
     */
    public void closeWifiAp() {
        WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
        if (isWifiApEnabled()) {
            try {
                Method method = wifiManager.getClass().getMethod("getWifiApConfiguration");
                method.setAccessible(true);
                WifiConfiguration config = (WifiConfiguration) method.invoke(wifiManager);
                Method method2 = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
                method2.invoke(wifiManager, config, false);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 開熱點手機獲得其他連接配接手機IP的方法
     *
     * @return 其他手機IP 數組清單
     */
    public ArrayList<String> getConnectedIP() {
        ArrayList<String> connectedIp = new ArrayList<String>();
        try {
            BufferedReader br = new BufferedReader(new FileReader(
                    "/proc/net/arp"));
            String line;
            while ((line = br.readLine()) != null) {
                String[] splitted = line.split(" +");
                if (splitted != null && splitted.length >= 4) {
                    String ip = splitted[0];
                    if (!ip.equalsIgnoreCase("ip")) {
                        connectedIp.add(ip);
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return connectedIp;
    }


}
           

裡面還少了一種WPS連接配接,這個如果需要,大家在自己添加上去了。

整個流程下來代碼還是挺多的,至于哪些地方需要注意的一時半會也說不完,也忘記了我開發過程遇到哪些問題了~~~間歇性失憶,啊哈哈哈

但是我還是要說一下:

1.可能會有人注意到,為什麼我使用ssid時,有時是直接使用,有時又需要加上雙引号"\""+ ssid + "\""這樣子,

這是因為如果你是從 WifiConfiguration 中擷取到的ssid的話,他預設會有雙引号,但是從ScanResult等擷取到ssid是沒有雙引号的,

是以為了比對隻好加上了。是以,在配置 WifiConfiguration時ssid和密碼都需要我們手動加上雙引号,他預設格式是這樣,不按照這個來會出現錯誤。

2.關于AP方面,目前開放的方法能直接開啟,是以這部分的内容全是通過反射機制進行的,我也是參考了一些部落格寫的,具體我自己沒試過。

3.其他有疑問的話,就在評論中提問吧~這樣友善大神們給你回複。

後面我寫了一個測試小程式,除了AP沒有測試外,其他功能正常使用,和系統的wifi功能差不多哦~

下面是幾張截圖:

掃描-擷取掃描結果

Android/安卓開發之WIFI的基本應用

點選連接配接(已經儲存好的)wifi - -分别會顯示正在連接配接...- - 正在擷取ip...  - - 已連接配接

Android/安卓開發之WIFI的基本應用

連接配接沒有儲存的wifi --彈出輸入密碼框(如果是沒加密不會彈出,而是直接連接配接),确認之後就連接配接

Android/安卓開發之WIFI的基本應用

如果點選已經連接配接的wifi,就可以選擇斷開還是忘記(不儲存)

Android/安卓開發之WIFI的基本應用

大概就這樣了。接下去可能會寫連接配接上wifi之後進行區域網通訊相關的。

完整demo github位址:https://github.com/nongchengqi/WifiConn2

附上activity的代碼:

package cn.small_qi.wificonn;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private ListView list;
    private WifiAdapter adapter;
    private WiFiAdmin admin;
    private static final int PERMISSION_WIFI_CODE = 1001;
    private static final int PERMISSION_FILE_CODE = 1002;
    private int curPosition=-1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int code = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
            if (code != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_FILE_CODE);
            }
        }
        initList();
        setListener();
        setStateListener();


    }


    private void initList() {
        admin = WiFiAdmin.getInstance(this);
        list = (ListView) findViewById(R.id.list);
        adapter = new WifiAdapter(this);
        list.setAdapter(adapter);
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                curPosition = position;
                final ScanResult result = adapter.getItem(position);
                if (admin.getConnectInfo().getSSID().equals("\""+result.SSID+"\"")){
                    new AlertDialog.Builder(MainActivity.this)
                            .setTitle("是否斷開連接配接?")
                            .setPositiveButton("斷開", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                   admin.disconnectWifi();
                                }
                            })
                            .setNegativeButton("不儲存", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    admin.forgetWifi(result.SSID);
                                }
                            })
                            .create().show();
                    return;
                }
                final int security =admin.getSecurity(result) ;
                int netid = admin.isWifiConfig(result.SSID);
                if ( netid == -1) {
                    if (security != WiFiAdmin.SECURITY_NONE) {
                        final EditText pwdEt = new EditText(MainActivity.this);
                        //彈出輸入密碼對話框
                        new AlertDialog.Builder(MainActivity.this)
                                .setView(pwdEt)
                                .setTitle("請輸入密碼")
                                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        admin.configWifi(result, pwdEt.getText().toString(),security);
                                       admin.connectWifi(admin.isWifiConfig(result.SSID));
                                    }
                                })
                                .setNegativeButton("取消", null)
                                .create().show();
                    } else {
                        admin.configWifi(result, "",security);
                        admin.connectWifi(admin.isWifiConfig(result.SSID)) ;
                    }
                } else {
                    admin.connectWifi(netid);
                }
            }
        });
    }

    private void setListener() {
        findViewById(R.id.close).setOnClickListener(this);
        findViewById(R.id.open).setOnClickListener(this);
        findViewById(R.id.scan).setOnClickListener(this);
        findViewById(R.id.info).setOnClickListener(this);
        findViewById(R.id.conn).setOnClickListener(this);
    }
    private void setStateListener() {
        admin.addWifiStateChangeListener(new WiFiAdmin.WifiStateChangeListener() {
            @Override
            public void onSignalStrengthChanged(int level) {

            }

            @Override
            public void onWifiConnecting() {
                adapter.updateState(0,curPosition);
            }

            @Override
            public void onWifiGettingIP() {
                adapter.updateState(1,curPosition);
            }

            @Override
            public void onWifiConnected() {
                adapter.updateState(2,curPosition);
            }

            @Override
            public void onWifiDisconnect() {
                adapter.updateState(4,curPosition);

            }

            @Override
            public void onWifiEnabling() {

            }

            @Override
            public void onWifiEnable() {

            }

            @Override
            public void onPasswordError() {
                adapter.updateState(3,curPosition);
            }

            @Override
            public void onWifiIDChange() {

            }
        });
    }


    private void checkPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int code = ContextCompat.checkSelfPermission(this, Manifest.permission_group.LOCATION);
            if (code != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_WIFI_CODE);
            } else {
                admin.startWifiScan();
                adapter.addAllWifis(admin.getScanResults());
            }
        } else {
            admin.startWifiScan();
            adapter.addAllWifis(admin.getScanResults());
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        admin.removeWifiStateChangeListener();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_WIFI_CODE:
                if (grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                    admin.startWifiScan();
                    adapter.addAllWifis(admin.getScanResults());
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
                break;

        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.close:
                admin.closeWifi();
                break;
            case R.id.open:
                admin.openWifi();
                break;
            case R.id.scan:
                //6.0權限
                checkPermission();
                break;
            case R.id.info:
                showInfo();
                break;
            case R.id.conn:
                if (admin!=null&&admin.getConnectInfo().getIpAddress()!=0){
                    startActivity(new Intent(MainActivity.this,ConnActivity.class));
                }else{
                    Toast.makeText(this, "請先連接配接Wifi或者等待Wifi連接配接成功", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    private void showInfo() {
        WifiInfo info = admin.getConnectInfo();
        if (info == null) {
            Toast.makeText(MainActivity.this, "目前未連接配接到WIFI", Toast.LENGTH_SHORT).show();
            return;
        }
        new AlertDialog.Builder(MainActivity.this)
                .setTitle("目前連接配接WIFI資訊:")
                .setMessage(info.getSSID() + "\n" + info.getMacAddress() + "\n" + WiFiAdmin.parseIPAddressToString(info.getIpAddress()) + "\n" +
                        info.getLinkSpeed() + "\n" + info.getBSSID() + "\n" + info.getRssi())
                .create()
                .show();
    }
}
           

xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:id="@+id/open"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="打開" />

            <Button
                android:id="@+id/close"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="關閉" />

            <Button
                android:id="@+id/scan"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="掃描" />

            <Button
                android:id="@+id/info"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="資訊" />

            <Button
                android:id="@+id/conn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="通訊" />
        </LinearLayout>
    </HorizontalScrollView>

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>

</LinearLayout>
           

--- 轉載請注明本文位址---