Connect vs Bind

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

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

 

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

Connect (requestNetwork)

        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

    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

 

GitHub - cornpip/android_network_bind_example

Contribute to cornpip/android_network_bind_example development by creating an account on GitHub.

github.com

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

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

 

테스트 흐름

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

결과

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