1

I'm trying to send data over a specific network interface (Wi-Fi or cellular) on Android but all the methods I've tried just return the primary network interface. In general this means Android returns Wi-Fi when it's available or cellular when it's not.

Is there a way to get either a Network or NetworkInterface to connect to for the non-primary network? I'd prefer a Network because I can use its socket factory with OkHttp but if it's not possible I'm fine with binding a Socket to a specific interface and doing the HTTP work myself.

ConnectivityManager.registerNetworkCallback

I registered a network callback with the following request:

val networkRequest = NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .build()

I also tried registering separate requests for a specific network types:

val wifiNetworkRequest = NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
  .build()

val cellularNetworkRequest = NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
  .build()

All of these appear to work the same as registerDefaultNetworkCallback. The newer registerBestMatchingNetworkCallback and the deprecated getAllNetworks also return just the active network.

NetworkInterface.getNetworkInterfaces

Not much to say here except that it doesn't work and behaves the exact same as ConnectivityManager

getifaddrs

My final attempt because I figured if anything would behave differently it would be the low level Linux based C-API but sadly it behaves the same as all the other methods.

2
  • Pardon if my understanding is wrong. Socket just need a valid connection to your server be it via WiFi or Cellular. Only one connection is used at a time which is the primary connection type. if you want to target a specific connection type say cellular than you need to notify the user to turn off the WiFi. Commented Jun 17 at 9:02
  • Yeah. I'm trying to replicate what I'm doing on iOS where an NWConnection can be tied to a specific NWInterfaceType. I have a working iOS app where I can show the user information about each of their network interfaces (current IP, ASN, rough location, etc). I would like to do the same for the Android app. Commented Jun 17 at 9:28

1 Answer 1

1
+500

Calling NetworkInterface.getNetworkInterfaces returns

information for NetworkInterfaces associated with an InetAddress.

If both, cellular and WiFi interface have an IP, it will return both. Take Ning as an example. It shows the VPN interface, WiFi and cellular. Each only shows when it's enabled (pictures below).

Ning uses getNetworkInterfaces in InterfaceScanner.kt:

NetworkInterface.getNetworkInterfaces().asSequence().flatMap { networkInterface ->
    networkInterface.interfaceAddresses.asSequence().map {
        val addr = it.address
        if (!addr.isLoopbackAddress && addr is Inet4Address) {
            NetworkResult(addr, it.networkPrefixLength, networkInterface.displayName, networkInterface.displayName)
        } else {
            null
        }
    }.filterNotNull()
}.toList()

Troubleshooting

  • Check that you have apropriate permissions
  • Force enable mobile data interface:
    1. Enable developer options
    2. Close and reopen the Settings app
    3. Go to Developer options and, under Networking, enable “Mobile data always active”

Further considerations

If you want to see interfaces that don't have an IP, have a look at VPN Hotspot for example. The app needs root but the author also lists the required permissions and explains in detail why it needs root.

Android docs say this information is available for system apps:

Note that information about NetworkInterfaces may be restricted. For example, non-system apps will only have access to information about NetworkInterfaces that are associated with an InetAddress.

Though running ip a in Termux shows me all available interfaces. You could try to call it from your app as well.


Mobile data disabled Mobile data enabled
2 interfaces 3 interfaces with cell
Sign up to request clarification or add additional context in comments.

4 Comments

Interesting. I've seen other Android devices where it does work so I'm starting to wonder if it's some limitation of the test device I have. Either way this is useful information! Thanks.
Good to hear. What does ip a in a shell report? For me it's generally in line with getNetworkInterfaces. I.e. if an interface has an IP, it should show up from the API, if it hasn't it does not.
I figured it out. It was an issue with my specific Android device. The final solution, for me, was: 1. Enable developer options 2. Close and reopen the Settings app 3. Go to Developer options and, under Networking, enable “Mobile data always active”
Good to know! I edited the solution into the answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.