현재 단말의 네트워크 상태를 확인하고 싶은 경우가 있습니다. 네트워크 상태를 확인하기 위해서 ConnectivityManager를 사용합니다. 이번 글에서 네트워크 상태를 알림 받는 방법 과  단순히 연결 상태 뿐만 아니라 네트워크 전송(Transpo...

[안드로이드][코틀린] 네트워크 상태 읽기 (Transport / Capabilities)

현재 단말의 네트워크 상태를 확인하고 싶은 경우가 있습니다.

네트워크 상태를 확인하기 위해서 ConnectivityManager를 사용합니다.

이번 글에서 네트워크 상태를 알림 받는 방법

 단순히 연결 상태 뿐만 아니라 네트워크 전송(Transport) 및 기능(Capabilities)에 대해 정리하려고 합니다.


**네트워크 전송(Transport) : Mobile Data, WiFi Bluetooth 등등

**네트워크 기능(Capabilities) : 인터넷, 데이터 무제한 등등








1. 네트워크 상태 알림 받기

별도의 NetworkManager 클래스를 만들었습니다.

해당 클래스는 NetworkCallback을 상속받도록 합니다.

class NetworkManager(context: Context) : ConnectivityManager.NetworkCallback() {

private val tag = "NetworkManager"
private val connectivityManager = context.getSystemService(ConnectivityManager::class.java)

fun registerNetworkCallback() {
connectivityManager.registerDefaultNetworkCallback(this)
}

fun unregisterNetworkCallback() {
connectivityManager.unregisterNetworkCallback(this)
}

override fun onAvailable(network: Network) {
super.onAvailable(network)

Log.d(tag, "network connected : $network")
}

override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities)

Log.d(tag, "network capabilities changed : $network")
}

override fun onLost(network: Network) {
super.onLost(network)

Log.d(tag, "network disconnected : $network")
}
}



각각의 메서드를 간략하게 살펴보자면 아래와 같습니다.

 - registerNetworkCallback : 네트워크 연결 상태 알림 등록

 - unregisterNetworkCallback : 네트워크 연결 상태 알림 등록 해제

 - onAvailable : 네트워크가 연결되었을 때 호출

 - onCapabilitiesChanged : 네트워크 기능이 변경되었을 때 호출 (또는 변경이 없더라도 호출)

 - onLost : 네트워크 연결이 끊어졌을 때 호출



아래 코드는 사용하는 예시입니다.

class MainActivity : AppCompatActivity() {

private val tag = "NetworkManager"
private lateinit var binding: ActivityMainBinding
private lateinit var networkManager: NetworkManager

override fun onDestroy() {
super.onDestroy()

networkManager.unregisterNetworkCallback()
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

networkManager = NetworkManager(this)
networkManager.registerNetworkCallback()
}
}








2. 네트워크 전송(Transport) 및 기능(Capabilities): NetworkCapabilities

단순히 연결 상태에 끝나지 않고 현재 네트워크에 대한 세부적인 내용이 필요한 경우가 있을 수 있습니다.

이때 NetworkCapabilities 객체를 활용할 수 있습니다.

// 현재 네트워크의 NetworkCapabilities 가져오기
val currentNetwork = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork)

 

해당 객체에는 전송(Transport)과 기능(Capabilities)이 캡슐화되어 있으며,

네트워크의 다양항 정보를 확인 할 수 있습니다.

(ex "네트워크 전송 수단이 뭐지?", "인터넷 지원되나?", "데이터 전송량 제한이 없는 상태를 알고 싶은데.." 등등)









3. 네트워크 전송(Transport) 확인

단말의 네트워크 전송(Transport)에는 대표적으로 Mobile Data, WiFi, Bluetooth가 있습니다.

현재 사용되는 네트워크가 어떤 전송을 사용하는지는 아래와 같이 확인할 수 있습니다.

fun isNetworkWiFi(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
}

fun isNetworkMobileData(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
}

fun isNetworkBluetooth(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)
}



 - TRANSPORT_WIFI : 네트워크가 WiFi 전송을 사용함을 나타냅니다.

 - TRANSPORT_CELLULAR : 네트워크가 모바일 데이터 전송을 사용함을 나타냅니다.

 - TRANSPORT_BLUETOOTH : 네트워크가 Bluetooth 전송을 사용함을 나타냅니다.








4. 네트워크 기능(Capabilities) 확인

단말의 네트워크 기능(Capabilities)에는 대표적으로 인터넷, 데이터 사용량 제한이 있습니다.

현재 사용되는 네트워크가 가지고 있는 기능 or 속성을 확인 할 수 있습니다.

fun isInternetSupported(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false

val hasCapabilityInternet = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
val hasCapabilityValidated = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)

return hasCapabilityInternet && hasCapabilityValidated
}

fun isNoDataLimit(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false

val hasCapabilityNotMetered = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
return hasCapabilityNotMetered
}



 - CAPABILITY_INTERNET : 네트워크가 인터넷에 연결할 수 있는 상태를 나타냅니다.

 - CAPABILITY_VALIDATED : 네트워크가 연결이 성공적으로 확인되었음을 나타냅니다.

 - CAPABILITY_NOT_METERED : 네트워크가 데이터 전송량 제한이 없음을 나타냅니다.


(여기서 잠깐..!!)

CAPABILITY_INTERNET 의 경우 인터넷에 도달할 수 있는 구성이 완료된 상태일 뿐이고,

실질적으로 인터넷 연결이 발견되었다는 CAPABILITY_VALIDATED 상태를 함께 체크해야합니다!








5. 마무리

네트워크 상태에는 다양한 기능 or 속성을 가지고 있기 때문에 필요한 정보를 다루면 좋을 것 같습니다. 

아래 문서에서 보다 자세한 네트워크 정보를 확인하실 수 있습니다.

Android Developer : NetworkCapabilities


끝으로 몇 가지 테스트해보면서 작성했던 전체 코드를 남깁니다.

[NetworkManager.kt]

class NetworkManager(context: Context) : ConnectivityManager.NetworkCallback() {

private val tag = "NetworkManager"
private val connectivityManager = context.getSystemService(ConnectivityManager::class.java)

fun registerNetworkCallback() {
connectivityManager.registerDefaultNetworkCallback(this)
}

fun unregisterNetworkCallback() {
connectivityManager.unregisterNetworkCallback(this)
}

fun isNetworkWiFi(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
}

fun isNetworkMobileData(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
}

fun isNetworkBluetooth(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)
}

fun isNetworkConnected(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false
return true
}

fun isInternetSupported(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false

val hasCapabilityInternet = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
val hasCapabilityValidated = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)

return hasCapabilityInternet && hasCapabilityValidated
}

fun isNoDataLimit(): Boolean {
val currentNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) ?: return false

val hasCapabilityNotMetered = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
return hasCapabilityNotMetered
}

fun checkCurrentNetwork() {
val currentNetwork = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork)
if (capabilities != null) {
// Check Transport
val hasTransportMobileData = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
val hasTransportWiFi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
val hasTransportBluetooth = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)
val hasTransportEthernet = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
val hasTransportVPN = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)

// Check Capability
val hasCapabilitySupl = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)
val hasCapabilityInternet = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
val hasCapabilityValidated = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
val hasCapabilityNotMetered = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
val hasCapabilityTrusted = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
val hasCapabilityNotRoaming = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)

if (hasTransportMobileData) Log.d(tag, "NetworkTransport : TRANSPORT_CELLULAR")
if (hasTransportWiFi) Log.d(tag, "NetworkTransport : TRANSPORT_WIFI")
if (hasTransportBluetooth) Log.d(tag, "NetworkTransport : TRANSPORT_BLUETOOTH")
if (hasTransportEthernet) Log.d(tag, "NetworkTransport : TRANSPORT_ETHERNET")
if (hasTransportVPN) Log.d(tag, "NetworkTransport : TRANSPORT_VPN")

if (hasCapabilitySupl) Log.d(tag, "NetworkCapability : NET_CAPABILITY_SUPL")
if (hasCapabilityInternet) Log.d(tag, "NetworkCapability : NET_CAPABILITY_INTERNET")
if (hasCapabilityValidated) Log.d(tag, "NetworkCapability : NET_CAPABILITY_VALIDATED")
if (hasCapabilityNotMetered) Log.d(tag, "NetworkCapability : NET_CAPABILITY_NOT_METERED")
if (hasCapabilityTrusted) Log.d(tag, "NetworkCapability : NET_CAPABILITY_TRUSTED")
if (hasCapabilityNotRoaming) Log.d(tag, "NetworkCapability : NET_CAPABILITY_NOT_ROAMING")
}

val linkProperties = connectivityManager.getLinkProperties(currentNetwork)
if (linkProperties != null) {
// Check LinkProperty
Log.d(tag, "LinkProperties : interfaceName ${linkProperties.interfaceName}")
Log.d(tag, "LinkProperties : linkAddresses ${linkProperties.linkAddresses}")
Log.d(tag, "LinkProperties : dnsServers ${linkProperties.dnsServers}")
}
}

override fun onAvailable(network: Network) {
super.onAvailable(network)

Log.d(tag, "network connected : $network")

checkCurrentNetwork()
}

override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities)

Log.d(tag, "network capabilities changed : $network")

//checkCurrentNetwork()
}

override fun onLost(network: Network) {
super.onLost(network)

Log.d(tag, "network disconnected : $network")
}
}


[MainActivity.kt]

class MainActivity : AppCompatActivity() {

private val tag = "NetworkManager"
private lateinit var binding: ActivityMainBinding
private lateinit var networkManager: NetworkManager

override fun onDestroy() {
super.onDestroy()

networkManager.unregisterNetworkCallback()
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

networkManager = NetworkManager(this)
networkManager.registerNetworkCallback()

binding.btnCheckNetwork.setOnClickListener {

networkManager.checkCurrentNetwork()

Log.i(tag, "isNetworkMobileData ${networkManager.isNetworkMobileData()}")
Log.i(tag, "isNetworkWiFi ${networkManager.isNetworkWiFi()}")
Log.i(tag, "isNetworkBluetooth ${networkManager.isNetworkBluetooth()}")
Log.i(tag, "isInternetSupported ${networkManager.isInternetSupported()}")
Log.i(tag, "isNoDataLimit ${networkManager.isNoDataLimit()}")
}
}
}






[Reference]

Android Developer : 네트워크 상태 읽기








0 comments: