📶
ConnectivityManagerをつかってSSIDを取ろうとすると<unknown>になる
背景
WifiManager.getConnectionInfo
が deprecatedになっていていた.
そこでConnecitivityManagerを利用して置き換えてみたのだけど、下記のように取得すると ssid = <unknown ssid>
となってしまう.
fun requestWifiInfo(context: Context) {
val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val wifi = (manager.getNetworkCapabilities(manager.activeNetwork)?.transportInfo as? WifiInfo) ?: return
println(wifi.ssid) // <unknown ssid>
println(wifi.bssid) // 02:00:00:00:00:00
}
}
解決策
2点がポイントだった.
- permissionに必要なpermissionを追加する.
-
FLAG_INCLUDE_LOCATION_INFO
を NetworkCallbackの引数に渡してリクエストし、onCapabilitiesChangedで正しい値を取得する.
permission
AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
code
fun requestWifiInfo(context: Context, onResult: (WifiInfo) -> Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
requestNetworkCapability(manager, onResult)
} else {
val manager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
val info: WifiInfo = manager.connectionInfo
onResult(info)
}
}
@RequiresApi(Build.VERSION_CODES.S)
fun requestNetworkCapability(manager: ConnectivityManager, onResult: (WifiInfo) -> Unit) {
val request = NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI)
.build()
// FLAG_INCLUDE_LOCATION_INFOを指定しないとWifiInfoが取得できない
val callback = object : NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
val wifi =
(networkCapabilities.transportInfo as? WifiInfo) ?: return@onCapabilitiesChanged
// ここで得られたwifiのssid情報は正しく得られる.
onResult(wifi)
}
override fun onAvailable(network: Network) {
super.onAvailable(network)
val wifi = (manager.getNetworkCapabilities(network)?.transportInfo as? WifiInfo)
?: return@onAvailable
// ここで得られたwifiのssid情報はunknownになるが...
}
}
manager.registerNetworkCallback(request, callback)
manager.requestNetwork(request, callback)
}
なぜ?
ssidなどのwifi情報は位置情報にセンシティブなデータだとして、必要とされる権限が強くなった.
このせいでssidを取得するまでの手順がややこしくなっている. (とくにAPI Level 33~)
Discussion