포스트

Android Network Binding: Switching Wi-Fi and Cellular

Android Network Binding: Switching Wi-Fi and Cellular

이 글은 Tistory에서 이전된 포스팅입니다. 원본은 여기에서 확인할 수 있습니다.

Connect vs Bind

Connect: 안드로이드는 Wi-Fi와 셀룰러 네트워크를 동시에 연결할 수 있다.

Bind: 연결된(사용 가능한) 네트워크 중 하나를 프로세스에 바인딩하여 해당 네트워크를 사용할 수 있다.

프로세스가 사용하는 네트워크는 바인딩된 네트워크이며, 바인딩하지 않으면 Android 시스템이 적절한 네트워크를 선택한다.

Connect (requestNetwork)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
        val specifier = WifiNetworkSpecifier.Builder()
            .setSsid(ssid)
            .setWpa2Passphrase(password)
            .build()

        val request = NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .setNetworkSpecifier(specifier)
            .build()

        val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val hasResponded = AtomicBoolean(false)

        deviceNetworkCb = object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                if (hasResponded.compareAndSet(false, true)) {
                    timeoutHandler.removeCallbacks(timeoutRunnable!!)
                    deviceNetwork = network
                    bindProcessToNetworkIfNeeded(network) { msg -> setMessage(msg) }
                    setMessage("✅ 연결 성공")
                }
            }

            override fun onUnavailable() {
                if (hasResponded.compareAndSet(false, true)) {
                    timeoutHandler.removeCallbacks(timeoutRunnable!!)
                    setMessage("❌ 연결 실패")
                }
            }
        }

        cm.requestNetwork(request, deviceNetworkCb!!)

Connect/Bind 모두 ConnectivityManager 객체를 통해 실행할 수 있다.

requestNetwork()는 요청할 네트워크와 콜백 함수를 지정할 수 있다.

요청한 네트워크를 사용할 수 없는 경우, 콜백은 호출되지 않는다.

SSID와 PassPhrase를 지정해 특정 Wi-Fi에 연결할 수도 있고,

인터넷이 가능한 네트워크만 요청하도록 옵션을 설정할 수도 있다.

Bind

1
2
3
4
5
    private fun bindProcessToNetworkIfNeeded(bindNetwork: Network?, setMessage: (String) -> Unit) {
        ...
        val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val success = cm.bindProcessToNetwork(bindNetwork)
        ...

bindProcessToNetwork()는 Bind 동작에 해당한다.

requestNetwork()만 호출하고 바인딩하지 않으면, Android 시스템은 가장 적절한 네트워크를 자동으로 선택해 사용한다.

예를 들어, requestNetwork()로 Wi-Fi에 연결을 요청했더라도 해당 Wi-Fi에 인터넷 연결이 없으면, 시스템은 셀룰러 네트워크를 기본으로 사용한다.

Example

https://github.com/cornpip/android_network_bind_example

Wi-Fi와 셀룰러 네트워크 간의 바인딩을 전환하며 API 요청을 테스트해보자.

테스트 환경에서 Wi-Fi는 인터넷이 연결되지 않은 AP이고, 셀룰러는 인터넷이 가능한 네트워크이다.

테스트 흐름

  1. 인터넷이 되지 않는 Wi-Fi에 requestNetwork()로 연결한다.
  2. 셀룰러와 Wi-Fi를 바꿔가면 binding 한다.
  3. API 요청을 실행한다.

결과

  • Wi-Fi에 바인딩된 상태에서는 API 요청이 실패한다.
  • 셀룰러에 바인딩된 상태에서는 API 요청이 성공한다.

이 기사는 저작권자의 CC BY-NC 4.0 라이센스를 따릅니다.