Accessing a locally running server on a physical Android device

Suppose you have a local server is running on localhost:8085. To access this from an Android emulator is straightforward. Just hit http://10.0.2.2:8085. However, with a physical device, the address 10.0.2.2 will not necessarily work.

To get it to work, the approach I use to first connect both my development machine and phone to the same network, usually Wifi. I then check the IP address of my machine by running the ifconfig command to list all active network interfaces. Normally, the correct address will be under the en0 interface. You can of course check for the IP address under Network settings of the operating system. If say the IP address is 192.168.0.37, then using it on the physical Android device will work.

This is not convenient since I have to keep checking and changing the IP addresses every time I change networks.

Generic Solution

A better approach is to create a build variant that will automatically get the development machine’s IP address and expose it to the physical Android device.

To do that, in the build.gradle file, I add a helper function to get the IP address of the development machine within my local network as:

1
2
3
4
5
6
def getLocalIp() {
new Socket().withCloseable { socket ->
socket.connect(new InetSocketAddress("google.com", 80))
return socket.getLocalAddress().toString().substring(1)
}
}

This function makes a socket connect to google.com. From the socket object, I retrieve my machine’s local address. Calling socket.getLocalAddress().toString() will return the address such as /192.168.0.37.

If you have a build variant for use with physical Android devices, simply call the function getLocalIp() at the point where you need your machine’s IP address.
This will always work even when you switch networks for as long as both your development machine and physical Android phone are connected to the same network.

Conclusion

In summary, my build.gradle file will typically look like this:

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
apply plugin: 'com.android.application'

android {
// buildToolsVersion:
buildTypes {
release: { // details }
debug: {// details}
}

productFlavors{
emulator {
buildConfigField("String", "BASE_URL", '"http://10.0.2.2:8085"')
// other build fields
}
physicalDevice {
buildConfigField("String", "BASE_URL", '\"http://' + getLocalIp() + ':8085"')
// other build fields
}
// other variants
}
// ...
}

def getLocalIp() {
new Socket().withCloseable { socket ->
socket.connect(new InetSocketAddress("google.com", 80))
return socket.getLocalAddress().toString().substring(1)
}
}