단말의 인터넷 연결상태 체크하기

이번 포스팅에서는 단말의 인터넷 연결상태를 체크하는 법에 대해 알아보도록 하겠습니다.

앱을 만들다보면 WIFI를 사용할 수 있는 환경에서 대용량 데이터를 다운로드하도록 하는 등의 처리를 위해 단말의 인터넷 연결상태를 체크해야 할 일이 있습니다. 이때 ConnectivityManager를 사용하면 단말이 어떤 접속환경을 통해 인터넷에 연결되어 있는지 확인할 수 있습니다.

# 권한추가

인터넷에 접근하고 네트워크 상태를 가져오기 위해 AndroidManifest.xml에 다음 권한을 추가합니다.

1
2
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

# 네트워크 타입 확인

우선은 단말이 연결된 네트워크가 와아파이인지 셀룰러인지 확인하는 코드를 써 보겠습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
private fun getNetworkType(context: Context): String {
    val connMgr =
        context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val nw = connMgr.activeNetwork ?: return "NO_CONNECTION"
        val actNw = connMgr.getNetworkCapabilities(nw) ?: return "NO_CONNECTION"
        return when {
            actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> "WIFI_STATE"
            actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> "CELLULAR_STATE"
            actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> "ETHERNET_STATE"
            else -> "NO_CONNECTION"
        }
    } else {
        val nwInfo = connMgr.activeNetworkInfo ?: return "NO_CONNECTION"
        return nwInfo.typeName
    }
}

기본은 ConnectivityManager 인스턴스를 만들고 그 인스턴스로부터 네트워크 타입을 가져오는 방식입니다. API Level 23 마시멜로우까지는 connMgr.activeNetworkInfo를 통해 NetworkInfo 인스턴스를 만든 뒤 typeName 프로퍼티로 네트워크 타입을 문자열 형태로 확인할 수 있었습니다.

그러나 마시멜로우 이상에서는 ConnectivityManageractiveNetwork 프로퍼티로 Network 인스턴스를 받아옵니다. 이 인스턴스를 getNetworkCapabilities로 전달하여 NetworkCapabilities의 인스턴스를 얻은 뒤 hasTransport를 실행하여 네트워크 타입을 가져오게 됩니다. 이 시점에서 접속이 확인되지 않을 경우 네트워크에 접속되지 않은 것입니다.

# 네트워크 접속여부 확인

NetworkInfo 인스턴스의 isConnected 메소드를 사용하면 현재 인터넷에 접속되어있는지를 확인할 수 있습니다. 그런데 이 메소드로는 버스나 공항에서 접속할 수 있는 인증이 필요한 와이파이에 대해서는 인증이 되지 않아서 실제로는 와이파이를 사용할 수 없어도 true를 반환하게 됩니다.

따라서 실제로 임의의 주소에 핑을 날려보는게 더 확실합니다. 구글에서는 이렇게 네트워크 접속을 확인할 때 쓰라고 Network Portal Detection 서비스를 제공하고 있는데요, 그 주소는 다음과 같습니다. http://clients3.google.com/generate_204

이 주소로 접속에 성공하면 HTTP 204 No Content 를 반환합니다. 204 응답이 돌아오면 단말이 인터넷을 사용할 수 있는 상태라는 거지요.

우선은 http://clients3.google.com/generate_204 에 접속하여 response code를 받아오는 함수를 작성합니다. 네트워크에 접속해야 하므로 비동기로 처리하기 위해 Thread 를 상속받도록 합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
private class CheckConnection(private val host: String) : Thread() {
    var isSuccess = false

    override fun run() {
        var urlConnection: HttpURLConnection? = null
        try {
            urlConnection = URL(host).openConnection() as HttpURLConnection
            urlConnection.setRequestProperty("User-Agent", System.getProperty("http.agent"))
            urlConnection.connectTimeout = 1000
            urlConnection.connect()
            val responseCode = urlConnection.responseCode
            if (responseCode == 204) {
                isSuccess = true
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        urlConnection?.disconnect()
    }
}

다음은 CheckConnection을 실행시켜주면 되겠죠. 스레드를 시작하고 204 응답이 돌아왔다면 true를 반환하는 함수를 만들어줍니다. 메인스레드에서 작업이 끝날때까지 대기하도록 하기 위해 join을 추가로 실행시켜 줍니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
private fun isOnline(): Boolean {
    val cc = CheckConnection("http://clients3.google.com/generate_204")
    cc.start()
    try {
        cc.join()
        return cc.isSuccess
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return false
}

이렇게 해서 단말의 네트워크 상태를 체크하는 법에 대해 알아보았습니다.

Built with Hugo
Theme Stack designed by Jimmy