0

TLDR: I am looking for a way to expose a POST endpoint from an Android app. Is this possible? If so, how?

Long story:

I want to receive data from Arduino devices on my android app. So I want a way to get this data through Wi-Fi (that may be a wrong assumption) but without internet connection. My current idea is to post the data from the Arduino to the smartphone over Wi-Fi.

enter image description here

The thing I don't know, and I didn't find answer yet is: Can I get data send to my hotspot Wi-Fi inside my app?

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Quentin M
  • 171
  • 2
  • 11
  • 1
    Securing this is rather difficult, but there are various libraries that implement HTTP servers in Android, such as koush's [AndroidAsync](https://github.com/koush/AndroidAsync#androidasync-also-lets-you-create-simple-http-servers). – CommonsWare Feb 14 '22 at 12:15
  • I will look into that it seems promising thx a lot. – Quentin M Feb 14 '22 at 14:02
  • I want to go with this solution because the library is more maintained than NanoHttpD. However, I think I am doing something wrong. My server start on localhost:7000 and when I try to ping from my laptop (connected to my phone over hotspot) I get nothing. For me I should not be using localhost but I don't know which hostname could I use ? – Quentin M Feb 14 '22 at 21:07
  • I did something like this : https://github.com/andreivisan/AndroidAsyncHttpServer/blob/master/app/src/main/java/server/http/android/MainActivity.java – Quentin M Feb 14 '22 at 21:13
  • Presumably, you would use the IP address of the phone. – CommonsWare Feb 14 '22 at 21:20

2 Answers2

1

To host endpoints inside your Android application you will need a sever to serve those endpoints. You can use the NanoHttpD for this.

Check this question to check how to use NanoHttpD in Android.

Taranmeet Singh
  • 1,199
  • 1
  • 11
  • 14
0

Thank you to both @CommonsWare and @Taranmeet Singh for helping to find my solution.

I build a small http server on my phone that can be reach through http call from my laptop.

Two points were not so obvious for me :

  1. the tecno
  2. the host ip

For the first point, you can use :

I choose the last option because :

  1. It used natively kotlin
  2. It is build and maintained by JetBrains, the other library were less maintained
  3. It is really light (10 lines to make it works)

To use Ktor you need to add this in your app gradle :

defaultConfig {
        ...
        multiDexEnabled true

    }

For the second point : by default you are bind and localhost, but you can change that :

embeddedServer(Netty, host = "192.168.43.1", port = 8080)

This ip is the default one for Android (it seems), you can also Utils method to get it : How to get IP address of the device from code?

fun getIPAddress(useIPv4: Boolean): String {
    try {
        val interfaces: List<NetworkInterface> =
            Collections.list(NetworkInterface.getNetworkInterfaces())
        for (intf in interfaces) {
            val addrs: List<InetAddress> = Collections.list(intf.inetAddresses)
            for (addr in addrs) {
                if (!addr.isLoopbackAddress) {
                    val sAddr = addr.hostAddress
                    //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
                    val isIPv4 = sAddr.indexOf(':') < 0
                    if (useIPv4) {
                        if (isIPv4) return sAddr
                    } else {
                        if (!isIPv4) {
                            val delim = sAddr.indexOf('%') // drop ip6 zone suffix
                            return if (delim < 0) sAddr.toUpperCase(Locale.ROOT) else sAddr.substring(
                                0,
                                delim
                            ).toUpperCase(Locale.ROOT)
                        }
                    }
                }
            }
        }
    } catch (ignored: Exception) {
    } // for now eat exceptions
    return ""
}

This work for me, hope it will help others.

Final code look like this:

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    embeddedServer(Netty, host = getIPAddress(true), port = 8080) {
        install(ContentNegotiation) {
            gson {}
        }
        routing {
            get("/") {
                call.respond(mapOf("message" to "Hello , this ktor server"))
            }
        }
    }.start(wait = false)
}

/**
 * Get IP address from first non-localhost interface
 *
 * @param useIPv4 true=return ipv4, false=return ipv6
 * @return address or empty string
 */
private fun getIPAddress(useIPv4: Boolean): String {
    try {
        val interfaces: List<NetworkInterface> =
            Collections.list(NetworkInterface.getNetworkInterfaces())
        for (intf in interfaces) {
            val addrs: List<InetAddress> = Collections.list(intf.inetAddresses)
            for (addr in addrs) {
                if (!addr.isLoopbackAddress) {
                    val sAddr = addr.hostAddress
                    //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
                    val isIPv4 = sAddr.indexOf(':') < 0
                    if (useIPv4) {
                        if (isIPv4) return sAddr
                    } else {
                        if (!isIPv4) {
                            val delim = sAddr.indexOf('%') // drop ip6 zone suffix
                            return if (delim < 0) sAddr.toUpperCase(Locale.ROOT) else sAddr.substring(
                                0,
                                delim
                            ).toUpperCase(Locale.ROOT)
                        }
                    }
                }
            }
        }
    } catch (ignored: Exception) {
    } // for now eat exceptions
    return ""
}}
Quentin M
  • 171
  • 2
  • 11