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 に記述するだけでは不十分で、動的に許可を得ないといけないこれも Android 6.0 からの仕様ので注意が必要です。

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

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

```xml




```

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

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

> 参考
>
> [Requesting Permissions at Run Time | Android Developers](https://developer.android.com/training/permissions/requesting.html)


```java
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 scanResults = wm.getScanResults();

        for (ScanResult scanResult : scanResults) {
            Log.d(TAG, scanResult.toString());
        }
    }
}
```

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

0 件のコメント: