2016/11/08

Android 6.0 以降で WifiManager.getScanResults() を普通に実行しても結果が空のリストになってしまう

かつては WifiManager.getScanResults() を実行するのに必要なパーミッションは android.permission.ACCESS_WIFI_STATE だけでした。

しかし、そのパーミッションを記述していても、 Android 6.0 (API 23 Marshmallow) 以降で WifiManager.getScanResults() を実行すると スキャン結果が0個になって しまいます。

追加のパーミッションが必要になった

実は、 Android 6.0 以降では、WifiManager.getScanResults() を実行するのに以下の どちらか のパーミッションも必要になりました。 ただ、先に書いたように、このパーミッションを取得していなくても、Exception が発生するのではなく、空のリストが返ってくるため、問題に気づきにくいのが厄介な点です。

  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION

参考

WifiManager#getScanResults() | Android Developers

パーミッションの取得方法

さらに、LOCATION 関連のパーミッションは AndroidManifest.xml に記述するだけでは不十分で、動的に許可を得ないといけない1ので注意が必要です。

以下に、android.permission.ACCESS_COARSE_LOCATION を取得する方法を示します。

まず、これまでと同様、AndroidManifest.xml に記述します。

1
2
3
4
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 
<!-- getScanResults() にはこちらも必要 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

加えて、Activity 等で動的にパーミッションを取得します。

以下に示したコードは必要最低限のものなので、具体的な実装は Android Developers も参考にしてください。

参考

Requesting Permissions at Run Time | Android Developers

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
50
51
public class MainActivity extends Activity {
    private final int PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION = 0;
 
    @Override
    protected void onResume() {
        super.onResume();
 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 既に許可されているか確認
            if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
                // 許可されていなかったらリクエストする
                // ダイアログが表示される
                requestPermissions(
                        new String[]{
                                Manifest.permission.ACCESS_COARSE_LOCATION
                        },
                        PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION);
                return;
            }
        }
 
        logScanResults();
    }
 
    @Override
    public void onRequestPermissionsResult(
            int requestCode,
            @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 
        if (requestCode == PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 許可された場合
            logScanResults();
        } else {
            // 許可されなかった場合
            // 何らかの対処が必要
        }
    }
 
    private void logScanResults() {
        WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
        List<ScanResult> scanResults = wm.getScanResults();
 
        for (ScanResult scanResult : scanResults) {
            Log.d(TAG, scanResult.toString());
        }
    }
}

上記を実行すると、 以下のようなダイアログが表示され、ユーザーの許可を求めるようになります。

  1. これも Android 6.0 からの仕様 
?

0 件のコメント: