AndroidHTTPD

From SolidStateDepot
Jump to: navigation, search

Introduction

AndroidHTTPD is an extremely thin and fast webserver intended for the Android platform. AndroidHTTPD can serve any file or content your Androd app can get its hands on. It can serve assets or resources (or another web service call or request). It can be used to serve no files and just handle REST requests. It's up to you to code how HTTP requests are handled in the provided RequestHandler interface.

I first wrote the code in Q1 2012 when I needed a down-and-dirty way to host a SpheroDunk game server - the world's first mobile wireless multiplayer game using Arduino, Android, and multiple Spheros. I've used NanoHTTPDPooled in at least two unpublished applications and it works as expected.

AndroidHTTPD can be download from github at https://github.com/tenaciousRas/NanoHTTPDPooled. There are two files, NanoHTTPDPooled and AndroidHTTPD. AndroidHTTPD is an Android-colored wrapper around NanoHTTPDPooled. NanoHTTPDPooled is based on the well-proven NanoHTTPD Java server.

Using an HTTP server on an Android device isn't highly recommended for most apps. First, for this to work you need a reliable Wifi internet connection. Second, due to cellular carrier network restrictions, and for most practical purposes, the web server on an Android phone is only accessible to other devices on the same Wifi network. I'm not sure if some handsets/devices block port 80 on the OS (i.e. the phone can't open any socket connections on port 80), but I haven't seen that so far and would expect that to be rare.

One potentially valid reason to run a web server in your Android app is to provide a REST API that other devices on the local network can access. Since HTTP is a simple and robust transport layer, you can have non-Android devices which communicate via HTTP and have those devices engage with an Android handset or tablet.

Java programmers will note that AndroidHTTPD is easily ported to a standard JVM for use in Java apps also - like NanoHTTPD.

Why Use AndroidHTTPD

  • Despite the limitations described above your Android application wants/needs to serve HTTP requests.
  • NanoHTTPDPooled - the parent class of AndroidHTTPD - is extremely thin. It is contained in one class, just over 1000 lines including whitespace.
  • AndroidHTTPD can be embedded in your app. You decide what HTTP requests to handle and how to handle them.
  • AndroidHTTPD is extremely fast. For example it can serve 1.1MB worth of HTML, CSS, JS, and PNG images (in almost 2-dozen requests) on an Acer A100 tablet in under 2.5 seconds.
  • AndroidHTTPD comes with very little functionality other than what you add. The default is to just serve files from a wwwroot that you specify (upon startup).
  • AndroidHTTPD is natively secure (although you can break this). That's because it doesn't actually execute any CGI scripts or run any code on the server (=Android device). Directory listing is disabled by default. Directory traversing is forbidden.
  • It's not a phone-wide server with its own deployment model, it's custom to your Android app.
  • It does not implement the Java Servlet specification. Since you're not writing code that's executed within a Java Servlet container (or in the case of Android, a port of the Servlet container), you're not bound by its constraints. For example, Android ports of Jetty require you to deploy your files to the server as you usually do, but this also means that interacting with your custom Android app just got much more difficult and slower.
  • It is not a cross compiled port of Apache or lighttpd. It does not pretend to act like a fully-featured port which in reality is very slow and only partially featured.
  • Pools HTTPSession objects form a simple connection pool that improves performance compared to NanoHTTPD.

Usage

  1. AndroidHTTPD is the Android-specific wrapper around NanoHTTPDPooled. AndroidHTTPD is the object most Android developers will use and interface with.
  2. AndroidHTTPD and NanoHTTPDPooled are designed to be easy to consume and customize. As such they have no package name definition. Copy AndroidHTTPD.java and NanoHTTPDPooled.java into a source-code folder in your Android project; then give both files valid package names.
  3. Create an implementation of the AndroidHTTPD.RequestReceived interface in your Android application. You will probably want to write code to do something in the onRequestReceived(...) method in your class.
  4. Create an instance of AndroidHTTPD from within your Activity or Service. Pass it the Android Context object, www-root path (can be blank or null, you don't have to serve files!), port number, and the request handler you implemented in the previous step.
  5. Call the #startServer() method on your AndroidHTTPD instance.

The following is a skeleton example of an Activity that starts an HTTP server using AndroidHTTPD.

public class MyHTTPServerActivity extends Activity implements RequestHandler {
        ...
	@Override
	public AndroidHTTPD.Response onRequestReceived(String uri, String method,
			Properties header, Properties parms, Properties files) {
		Log.v(TAG,
				new StringBuilder("#onRequestReceived uri=").append(uri)
						.append(", method=").append(method).append(", header=")
						.append(method).append(", parms=").append(method)
						.append(", files=").append(method).toString());
		return new Response(AndroidHTTPD.HTTP_OK,
					HTTPServer.MIME_PLAINTEXT, "Server Running!");
	}
        ...
	protected void onCreate(Bundle savedInstanceState) {
                ...
		super.onCreate(savedInstanceState);
		httpServer = new AndroidHTTPD(getBaseContext(),
				DEFAULT_HTTP_PORT,
				Environment.getExternalStorageDirectory().getAbsolutePath(),
				this);
		httpServer.startServer();
                ...
        }

The above example uses an Activity which implements the RequestHandler interface, so we pass a reference to "this" in the AndroidHTTPD constructor. It will serve any HTML files stored on the SD card - per the path in the request URL. In other words, a request of "/index.html" will try to serve index.html from the root of the mounted SD card.

Discover Android Device IP Address

Also, unless you use LogCat with ADB in verbose mode you won't know what the IP of the Android device is. This bit of code can be used to robustly get the local IP address on most Android devices:


	/**
	 * Gets the local IP address by looping over the
	 * {@link NetworkInterface#getNetworkInterfaces()}.
	 * 
	 * @return the IP address of the first network interface that isn't loopback
	 *         and isn't a linkLocalAddress
	 */
	public static InetAddress getLocalIpAddress() {
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface
					.getNetworkInterfaces(); en.hasMoreElements();) {
				NetworkInterface intf = en.nextElement();
				for (Enumeration<InetAddress> enumIpAddr = intf
						.getInetAddresses(); enumIpAddr.hasMoreElements();) {
					InetAddress inetAddress = enumIpAddr.nextElement();
					if (!inetAddress.isLoopbackAddress()
							&& !inetAddress.isLinkLocalAddress()) {
						return inetAddress;
					}
				}
			}
		} catch (SocketException ex) {
			Log.e(TAG, ex.toString());
		}
		return null;
	}