Android 10 時代の Connectivity Monitoring

ConnectivityManager.CONNECTIVITY_ACTIONAPI level 28 で、 ConnectivityManager.getActiveNetworkInfo()NetworkInfo クラスそのものは API level 29 で、それぞれ Deprecated になりました。 長きにわたり大変お世話になりました。

Android 10 で通信状態の変更を監視するには、 ConnectivityManager.registerNetworkCallback() を使いましょう。

サンプルコード

NetworkRequest で通知を受け取る条件を指定して NetworkCallback を登録します。

NetworkRequest は、 NetworkCapabilities クラスの定数を使って、通知を受け取る条件を細かく指定することができます。 ここではインターネットへの接続が確立されたネットワークに関する通知を受け取りたいので、 NET_CAPABILITY_INTERNETNET_CAPABILITY_VALIDATED を指定しました。

NetworkCallbackNetworkCapabilitiesAPI level 21 から使えるのですが、 NET_CAPABILITY_VALIDATEDAPI level 23 で追加された定数なので、 API 23 前後で従来の方法と分岐しています。

private val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

private fun registerNetworkCallback() {
  if (Build.VERSION.SDK_INT < 23) {
    context.registerReceiver(
      networkReceiver,
      IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
    )
  } else {
    val request = NetworkRequest.Builder()
      .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
      .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
      .build()
    cm.registerNetworkCallback(request, networkCallback)
  }
}

private fun unregisterNetworkCallback() {
  if (Build.VERSION.SDK_INT < 23) {
    context.unregisterReceiver(networkReceiver)
  } else {
    cm.unregisterNetworkCallback(networkCallback)
  }
}

ネットワークに接続されたときと切断されたときに、通信状態を取得します。

@RequiresApi(23)
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
  override fun onAvailable(network: Network?) = checkConnection()
  override fun onLost(network: Network?) = checkConnection()
}

@RequiresApi(23)
private fun checkConnection() {
  val activeNetworks = cm.allNetworks.mapNotNull { cm.getNetworkCapabilities(it) }.filter {
    it.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
      it.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
  }

  val isConnected = activeNetworks.isNotEmpty(),
  val isWiFi = activeNetworks.any { it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) }
}

NetworkCallback は、個々の Network に対して呼ばれます。 例えば Cellular が繋がっているときに WiFi に接続すると、 onAvailable()WiFi 接続が有効になったことが通知されたあとしばらく経ってから onLost() で Cellular の切断が通知されます。

また ConnectivityManager.getActiveNetwork() は、 WiFi を切って Cellular に切り替わる場合などで、すでに切断されたはずの WiFi Network を返すことがありました。

以上を踏まえて、何らかの通信状態の変更通知を受けたタイミングですべての Network を確認し、

  • インターネットへの接続が確立されたものがあるか
  • その中に WiFi はあるか

を判断するのが良さそうです。


出典: