2016/10/27

Android で Wi-Fi の接続状態を確認する

この記事は Android の Wi-Fi 実装に関する情報のまとめ の一部として書かれました

Wi-Fi 接続して、通信を行っているか等の状態を確認する方法です。

Android の Wi-Fi 接続状態を保持するクラスは WifiInfoNetwrokInfo の2種類があります。 前者は Wi-Fi に特化しているのに対し、後者は接続全般1をカバーします。 状況によって使い分けるのが良いでしょう。

WifiInfo を使うコード

wpa_supplicant が提供する情報を取得する方法です。

Wi-Fi 接続していない場合も null が返るのではなくINACTIVE な状態が返ります。

1
2
3
4
5
// Activity 等の Context 内で
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
WifiInfo wifiInfo = wm.getConnectionInfo();
 
WifiInfo.SupplicantState state = wifiInfo.getSupplicantState();

取得できる SupplicantState

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public enum SupplicantState implements Parcelable {
    DISCONNECTED,
    INTERFACE_DISABLED,
    INACTIVE,
    SCANNING,
    AUTHENTICATING,
    ASSOCIATING,
    ASSOCIATED,
    FOUR_WAY_HANDSHAKE,
    GROUP_HANDSHAKE,
    COMPLETED,
    DORMANT,
    UNINITIALIZED,
    INVALID
}

各状態については JavaDoc を参照のこと。

参考

SupplicantState | Android Developers

この SupplicantState ですが、JavaDoc の中に以下のような記述があります。

This is more fine-grained than most users will be interested in. In general, it is better to use NetworkInfo.State.

意訳すると以下のような感じでしょうか

この情報は多くのユーザーにとって詳細すぎる。一般的には NetworkInfo.State を使うほうが良い。

特別な理由が無いのであれば NetworkInfo を使っておいた方が良いのかもしれません。

NetworkInfo を使うコード1

getActiveNetworkInfo() で現在使用中のネットワーク情報を取得し、それが Wi-Fi かどうか確認するという方式です。

なお、ネットワーク接続がない状態だと networkInfonull になります。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Activity 等の Context 内で
ConnectivityManager connectivityManager =
        (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
 
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
        // シンプルな状態を取得
        NetworkInfo.State networkState = networkInfo.getState();
 
        // 詳細状態を取得
        // これを使うことはめったに無いと思われる
        NetworkInfo.DetailedState detailedState = networkInfo.getDetailedState();
}

取得できる State

1
2
3
4
5
6
7
8
public enum {
    CONNECTING,
    CONNECTED,
    SUSPENDED,
    DISCONNECTING,
    DISCONNECTED,
    UNKNOWN
}

取得できる DetailedState

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
public enum {
    /** Ready to start data connection setup. */
    IDLE,
    /** Searching for an available access point. */
    SCANNING,
    /** Currently setting up data connection. */
    CONNECTING,
    /** Network link established, performing authentication. */
    AUTHENTICATING,
    /** Awaiting response from DHCP server in order to assign IP address information. */
    OBTAINING_IPADDR,
    /** IP traffic should be available. */
    CONNECTED,
    /** IP traffic is suspended */
    SUSPENDED,
    /** Currently tearing down data connection. */
    DISCONNECTING,
    /** IP traffic not available. */
    DISCONNECTED,
    /** Attempt to connect failed. */
    FAILED,
    /** Access to this network is blocked. */
    BLOCKED,
    /** Link has poor connectivity. */
    VERIFYING_POOR_LINK,
    /** Checking if network is a captive portal */
    CAPTIVE_PORTAL_CHECK
}

NetworkInfo を使うコード2 (API Level 21 Lollipop 以降)

getAllNetworks() で使用可能な 全ての ネットワークを取得して、その中から Wi-Fi のものをチェックする方法です。

この方法の落とし穴は、getAllNetworks()接続している ネットワーク一覧しか返さないというところです。 つまり、一般的な端末では getAllNetworks().length は大抵 0 か 1 になります2。 ただし、モバイル接続から Wi-Fi 接続に切り替わる瞬間、少しの間だけ 2 になることもあるようです3

そのため、この方法は実質「NetworkInfo を使うコード1」と一緒と言って良いでしょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Activity 等の Context 内で
ConnectivityManager connectivityManager =
        (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
 
for (Network network : connectivityManager.getAllNetworks()) {
    NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
    if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
        // シンプルな状態を取得
        NetworkInfo.State state = networkInfo.getState();
 
        // 詳細状態を取得
        NetworkInfo.DetailedState detailedState = networkInfo.getDetailedState();
    }
}

取得できる状態は「NetworkInfo を使うコード1」と同じです。

NetworkInfo を使うコード3 (API Level 20 Kitkat 以前)

この方法は Lollipop 以降 Deprecated になりました。

なお、Wi-Fi 機能がハードウェア的に存在しない場合は、networkInfonull になります。

1
2
3
4
5
6
7
8
9
10
11
// Activity 等の Context 内で
ConnectivityManager connectivityManager =
        (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
 
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
 
// シンプルな状態を取得
NetworkInfo.State state = networkInfo.getState();
 
// 詳細状態を取得
NetworkInfo.DetailedState detailedState = networkInfo.getDetailedState();

取得できる状態は「NetworkInfo を使うコード1」と同じです。

WifiInfo を使うためのパーミッション

WifiInfo を使うコードを実行するには android.permission.ACCESS_WIFI_STATE パーミッションを AndroidManifest.xml で設定する必要があります。

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

NetworkInfo を使うためのパーミッション

NetworkInfo を使うコードを実行するには android.permission.ACCESS_NETWORK_STATE パーミッションを AndroidManifest.xml で設定する必要があります。

1
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  1. LTE等 
  2. 名前と挙動が合ってないし、あんまり使い勝手が良くないと思うのは私だけ? 
  3. 少なくとも、私の手元の Nexus 7 (2012) と Nexus 6P はそういう挙動でした 
?

0 件のコメント: