1. 程式人生 > >Android —— WIFI狀態相關的系統廣播

Android —— WIFI狀態相關的系統廣播

本文轉自:http://blog.csdn.net/kongxiuqi/article/details/52524500 這裡將原文規整了一下。

WIFI狀態變化會發送系統廣播,一些可用的系統廣播在WifiManger類中可以看到。

廣播一:WIFI 開關狀態變化的監聽

/**
 * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
 * enabling, disabling, or unknown. One extra provides this state as an int.
 * Another extra provides the previous state, if available.
 *
 * @see
#EXTRA_WIFI_STATE * @see #EXTRA_PREVIOUS_WIFI_STATE */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String WIFI_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_STATE_CHANGED"; // 自定義個Broadcast,並在Broadcast中判斷這個WIFI功能的開啟與關閉(與WIFI是否連線無關) if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) { int
wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0); swtch(wifiState) { case WifiManager.WIFI_STATE_DISABLED: Log.d("Tag", "--- WIFI狀態:已關閉WIFI功能 ---"); break; case WifiManager.WIFI_STATE_DISABLING: Log.d("Tag"
, "--- WIFI狀態:正在關閉WIFI功能 ---"); break; } }

各個狀態的值如下:

/**
 * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
 * it finishes successfully.
 *
 * @see #WIFI_STATE_CHANGED_ACTION
 * @see #getWifiState()
 */
public static final int WIFI_STATE_DISABLING = 0; // Wifi功能正在關閉中

/**
 * Wi-Fi is disabled.
 *
 * @see #WIFI_STATE_CHANGED_ACTION
 * @see #getWifiState()
 */
public static final int WIFI_STATE_DISABLED = 1; // Wifi功能已經關閉

/**
 * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
 * it finishes successfully.
 *
 * @see #WIFI_STATE_CHANGED_ACTION
 * @see #getWifiState()
 */
public static final int WIFI_STATE_ENABLING = 2; // Wifi功能正在開啟中

/**
 * Wi-Fi is enabled.
 *
 * @see #WIFI_STATE_CHANGED_ACTION
 * @see #getWifiState()
 */
public static final int WIFI_STATE_ENABLED = 3; // Wifi功能已經開啟

/**
 * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
 * or disabling.
 *
 * @see #WIFI_STATE_CHANGED_ACTION
 * @see #getWifiState()
 */
public static final int WIFI_STATE_UNKNOWN = 4; // Wifi處於未知狀態

廣播二:WIFI 連線狀態變化的監聽

/**
 * Broadcast intent action indicating that the state of Wi-Fi connectivity
 * has changed. One extra provides the new state
 * in the form of a {@link android.net.NetworkInfo} object. If the new
 * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of
 * the access point.
 * 
 * as a {@code String}.
 * @see #EXTRA_NETWORK_INFO
 * @see #EXTRA_BSSID
 * @see #EXTRA_WIFI_INFO
 */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";

// 監聽WIFI的連線狀態即是否連上了一個有效無線路由。
// 當上邊廣播的狀態是WifiManager.WIFI_STATE_DISABLING,和WIFI_STATE_DISABLED的時候,根本不會接到這個廣播(因為WIFI功能未開啟,所以不可能連線上有效WIFI)。
// 當上邊廣播接到廣播是WifiManager.WIFI_STATE_ENABLED狀態的同時也會接到這個廣播,當然剛開啟WIFI肯定還沒有連線到有效的無線  

        if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) {
            Parcelable parcelableExtra = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
            if (null != parcelableExtra) {
                NetworkInfo networkInfo = (NetworkInfo) parcelableExtra;
                NetworkInfo.State state = networkInfo.getState();
                boolean isConnected = state == NetworkInfo.State.CONNECTED;
                // WIFI已連線
                if (isConnected) {
                    // ...
                }
                // WIFI未連線
                else {
                    // ...
                }
            }
        }  

廣播三:WIFI 列表掃描完成

/**
 * An access point scan has completed, and results are available from the supplicant.
 * Call {@link #getScanResults()} to obtain the results. {@link #EXTRA_RESULTS_UPDATED}
 * indicates if the scan was completed successfully.
 */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";

wifi掃描完成,獲取wili列表 可以通過wifimanager的startScan主動發起掃描,掃描完成後會發送這個廣播

if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
    Log.e(TAG, "WifiManager.SCAN_RESULTS_AVAILABLE_ACTION");
    WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    List<ScanResult> list = wifiManager.getScanResults();
    for (int i = 0; i < list.size(); i++) {
        Log.e(TAG, list.get(i).toString());
        Log.e(TAG, "ScanResult SSID = " + list.get(i).SSID);
    }
}

getScanResults()只能得到當前可用的WIFI列表,獲取所有WIFI列表需用如下方法(該方法可以獲取以前連線過的WIFI)

/**
 * Return a list of all the networks configured in the supplicant.
 * Not all fields of WifiConfiguration are returned. Only the following
 * fields are filled in:
 * networkId
 * SSID
 * BSSID
 * priority
 * allowedProtocols
 * allowedKeyManagement
 * allowedAuthAlgorithms
 * allowedPairwiseCiphers
 * allowedGroupCiphers
 * 
 * @return a list of network configurations in the form of a list
 * of {@link WifiConfiguration} objects. Upon failure to fetch or
 * when when Wi-Fi is turned off, it can be null.
 */

public List<WifiConfiguration> getConfiguredNetworks() {
    try {
        return mService.getConfiguredNetworks();
    } catch (RemoteException e) {
        Log.w(TAG, "Caught RemoteException trying to get configured networks: " + e);
        return null;
    }
}

廣播四:補充

/**
 * Broadcast intent action indicating that a connection to the supplicant has
 * been established (and it is now possible
 * to perform Wi-Fi operations) or the connection to the supplicant has been
 * lost. One extra provides the connection state as a boolean, where {@code true}
 * means CONNECTED.
 * @see #EXTRA_SUPPLICANT_CONNECTED
 */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
    "android.net.wifi.supplicant.CONNECTION_CHANGE";

另外還有一個監聽網路狀態變化的廣播 ConnectivityManager.CONNECTIVITY_ACTION

/**
 * A change in network connectivity has occurred. A default connection has either
 * been established or lost. The NetworkInfo for the affected network is
 * sent as an extra; it should be consulted to see what kind of
 * connectivity event occurred.
 * <p/>
 * If this is a connection that was the result of failing over from a
 * disconnected network, then the FAILOVER_CONNECTION boolean extra is
 * set to true.
 * <p/>
 * For a loss of connectivity, if the connectivity manager is attempting
 * to connect (or has already connected) to another network, the
 * NetworkInfo for the new network is also passed as an extra. This lets
 * any receivers of the broadcast know that they should not necessarily
 * tell the user that no data traffic will be possible. Instead, the
 * receiver should expect another broadcast soon, indicating either that
 * the failover attempt succeeded (and so there is still overall data
 * connectivity), or that the failover attempt failed, meaning that all
 * connectivity has been lost.
 * <p/>
 * For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY
 * is set to {@code true} if there are no connected networks at all.
 */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";

如果我們需要判斷手機進入到某個WIFI的範圍就可以通過該廣播,以及掃描wifi列表進行實現,程式碼如下:

public class NetworkConnectChangedReceiver extends BroadcastReceiver {

        private static final String TAG = NetworkConnectChangedReceiver.class.getSimpleName();

        @Override
        public void onReceive(Context context, Intent intent) {
            // 處理掃描完成廣播,根據掃描結果比對是否進入了某個特定wifi範圍
            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
                Log.e(TAG, "WifiManager.SCAN_RESULTS_AVAILABLE_ACTION");
                WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                List<ScanResult> list = wifiManager.getScanResults();

                // 此處迴圈遍歷,可以根據SSID 或者MAC,與某個指定wifi進行對比,如果相等可以認為進入了該wifi的範圍
                for (int i = 0; i < list.size(); i++) {
                    Log.e(TAG, list.get(i).toString());
                    Log.e(TAG, "ScanResult SSID = " + list.get(i).SSID);
                }
            }
            // 這個監聽網路連線的設定,包括WIFI和移動資料的開啟和關閉。
            // 最好用的還是這個監聽。WIFI如果開啟,關閉,以及連線上可用的連線都會接到監聽。見log
            // 這個廣播的最大弊端是比上邊兩個廣播的反應要慢,如果只是要監聽wifi,我覺得還是用上邊兩個配合比較合適

            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
                ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo gprs = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
                NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
                Log.i(TAG, "網路狀態改變:" + wifi.isConnected() + " 3g:" + gprs.isConnected());
                Log.e(TAG, "ConnectivityManager.CONNECTIVITY_ACTION");
                NetworkInfo info = intent
                        .getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
                if (info != null) {
                    Log.e(TAG, "info.getTypeName()" + info.getTypeName());
                    Log.e(TAG, "getSubtypeName()" + info.getSubtypeName());
                    Log.e(TAG, "getState()" + info.getState());
                    Log.e(TAG, "getDetailedState()"
                            + info.getDetailedState().name());
                    Log.e(TAG, "getDetailedState()" + info.getExtraInfo());
                    Log.e(TAG, "getType()" + info.getType());

                    if (NetworkInfo.State.CONNECTED == info.getState()) {

                    } else if (info.getType() == 1) {
                        if (NetworkInfo.State.DISCONNECTING == info.getState()) {
                            Log.e(TAG, "disconnect");
                        }
                    }
                }

                // 開啟wifi掃描,掃描完成後傳送廣播
                WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                wifiManager.startScan();
            }
        }
    }

以上所有的廣播接收器需要動態註冊,如下:

 mIntentFilter = new IntentFilter();
 mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
 mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
 mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
 mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
 mIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
 registerReceiver(mReceiver, mIntentFilter);

或者在AndroidManifest中靜態註冊

<receiver android:name=".receiver.NetworkConnectChangedReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
        <action android:name="android.net.wifi.STATE_CHANGE" />
        <action android:name="android.net.wifi.SCAN_RESULTS" />
    </intent-filter>
</receiver>

最後需要在AndroidManifest中配置許可權

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />