EDIT: Own an Android device? Check out Gallus on the Play Store. It’s like Instagram brought Hyperlapse to Android, only a lot better.
Readers know that I am a fan of Go: The ease with which you can build highly-concurrent apps is an absolute delight.
Let me broaden that a bit: The ease with which you can build pretty much any kind of system or console style app, from a web service layer, a utility to connect A⇌B, or a financial calculation system, is a delight. That Go makes concurrency painless and incredibly robust is a nice bonus.
Not every project benefits from Go, but it’s worth learning about and considering in the stack.
One realm where Go has been considered the odd man out, however, is Android development. Which is a bit strange given their shared Google lineage. Indeed, in conversations about Go, it’s surprising how often people have the odd belief that Go is either some sort of lock-in to the Google App Engine (it is supported, but so are other languages. I use and abuse Go but have zero interest in the App Engine), or a tool for Android, where it actually has effectively no official support at all.
It is neither.
Go is a modern language with a surprisingly mature toolset. It builds native executables for x86, AMD64 (x86_64), and ARM, targeting the Linux, Windows, Darwin (OSX), and FreeBSD platforms. These executables have very few dependencies, meaning you can usually deploy a simple executable and…that’s it…the magic happens.
Looking at the above list you might notice that Go builds for Linux, which Android is of course based upon (Android 4.4 is based upon the Linux 3.8 kernel). And it can build for ARM, the architecture of most Android devices.
And you can build for all of these options on one single machine. If you’re running on Windows — it’s my base operating system — do yourself a favor and fire up a VM running Ubuntu or some other Linux distro for Go work. Once you have that you can easily build Go from the source, configuring it for full cross-platform builds (my only additions to that page is to ensure that you’ve installed mercurial and build-essential first — e.g. sudo apt-get install build-essential, and to use the release branch on the hg clone — hg clone -u release https://code.google.com/p/go).
From that single box with simple alterations of environment variables you can build to a huge variety of targets, including that ARM/Linux combo that most Android devices run.
… out pops an ARM executable that you can actually run on Android!
Just to take a moment to talk about the capabilities of smartphones, my Nexus 5 features 3x the memory of the virtual machine running this blog (a platform running MySQL, WordPress, Ubuntu 12.04.04 LTS Server, PHP5-fpm, among a wide variety of other system things, and doing so effortlessly). My smartphone is in practice running a faster processor.
But every now and then I run an app on it — a bonafide app that I built for a desktop or server — and I have that moment of disbelief and awe. “How is this possible?” I ask myself. It’s just a smartphone!
It still hasn’t entirely sunk in that it’s a powerful little computer of its own.
Anyways, back to the practical details of that executable, if you want to actually see that in practice you can copy the file to your Android device somewhere where you can set the executable bit (meaning not under sdcard). For instance /data/local/tmp. Open an ADB shell and chmod the file to 755 (setting the execute bit). Run it.
adb push myexecutable /data/local/tmp/myexecutable
chmod 755 myexecutable
Magic! A Go app running, in all probability perfectly, on your Android device.
Of course this isn’t terribly practical. You aren’t going to deploy executables and ask your clients to fire up ADB.
You can also package these stand-alone executables as a part of your encompassing APK. The Go app itself cannot (with current tooling) be the primary app, but it can be an assisting app if the situation called for it.
Scenarios and possibilities vary dramatically, however imagine that you’ve built a financial engine in Go. It takes a set of inputs and runs a set of complex rules and out pops, for instance, investment allocations. You run this on your server, but you’re putting together some mobile apps and it’d be optimal to have a local instance.
But you don’t want to port all of that code to Java. It’s complex and is fully tested, making heavy use of all of the concurrency primitives that would be difficult to port anyways, so such a task, and then added burden of trying to keep two or more versions in sync, is a high price to pay.
So don’t. Deploy your Go app.
Copy myexectuable under your Android project’s ./libs/armeabi/ folder. If you’re targeting one of the rare x86 Android devices, build to x86/Linux and copy the resulting binary to ./libs/x86 (and yes, you can include both in a single APK, and it will deploy whichever one is appropriate).
Here’s where things get a little hackish, but to good effect. Your executable needs to be prefaced with lib, and have the extension .so, to be bundled into the APK. For instance libmyexecutable.so. The mechanisms of the tooling are intended for shared-libraries generated by the NDK, but for our case that doesn’t matter. With the filename that meets the packaging regular expression’s needs your executable will be bundled and deployed when the app is installed.
You can avoid the hackishness using make files and custom specifying the APK construction, but ultimately it doesn’t matter: That the file isn’t a shared library is of no consequence, beyond looking weird. It is a bag of bits that will have the execute bit automatically set on deployment.
You can query where this binary baggage can be found at runtime via getApplicationInfo().nativeLibraryDir.
So now you have your main app running on the Android device, and you know the location of a Go executable that came along for the ride. Get that party started.
Process p = Runtime.getRuntime().exec(getApplicationInfo().nativeLibraryDir() + "/libmyexecutable.so");
How things work from here on out is up to you. Whether you use stdin/stdout to talk to the process, RPC, HTTP web service calls, ran TCP…whatever you do, you’re talking to another process. That other process has the same restrictions that your main Android app has (if you don’t have internet access, neither does it. It has the same file system limits. And so on. Going native doesn’t get you outside of the sandbox).
And of course you need to manage the lifetime of that second process. If your app is killed, as will it. If you want to preserve resources, shut it down. And so on.
None of this is to say that such a deployment strategy is ideal for what you are doing, but it’s interesting that you can do it, and it is one of those things that opens up possibilities that you might not have realized were there.
Edit: It’s worth noting that deploying a Go app as a service obviously isn’t ideal in many cases — a better solution would be a Go-developed library that could be used through JNI. The Go team is hard at work on that, and hopefully in the not too distant future the solutions you built in Go can be used without the hackery. Additionally note that Android L, in some builds, makes use of the SELinux functionality that restricts executables to those built using position-independent code. Go does not currently build such code, though surely the chain will add it in the near future.