The good news is that Node.js does run on Android. The bad news is that at least at the time I’m writing this the build process requires a few extra steps. Nothing too scary though. See below for details.
Building Node.js for Android
- Go find a Linux machine or maybe a Mac.
These instructions don’t currently work on Windows due to issues with the sh scripts being used. Yes, I did try the scripts in MINGW32 and no it didn’t work.
- Go download the Android NDK.
Which NDK to download does take a bit of attention. Most Android devices today are 32 bit so I want the Platform (32-bit target). But my Linux OS (Elementary OS) is 64 bit so I want Linux 64-bit (x86) under Platform (32-bit target).
- After downloading the NDK unzip it.
Let’s assume you put the NDK into ~/android-ndk-r10b.
- Go clone node.
Let’s assume you put that into ~/node. I am running these instructions off master branch.
- Check that you have all of node’s dependencies as listed here
I believe any modern Linux distro will have all of these already but just in case I decided to include the link.
- Go edit ~/node/android-configure and change ’arm-linux-androideabi-4.7’ to instead be ’arm-linux-androideabi-4.8.
This is the pull request that added basic Android support to Node. It contains some instructions. The first instruction will set up the build environment for Android. But the set up script is designed for an older version of the Android NDK. So we need to update it. Specifically 4.7 is apparently not supported by NDK 10 so I switched it to 4.8 which is. I decided to leave platform=android-9 for no particularly good reason.
- Run from inside of ~/node directory the command “source ./android-configure ~/android-ndk-r10b”
- Now go to ~/node/android-toolchain/bin and issue the command “mv python2.7 oldpython2.7 && ln -s /usr/bin/python2.7 python2.7”
The NDK appears to ship with its own version of Python 2.7 that doesn’t support a library (bz2) that is needed by files in the NDK. In any sane world this just means that the NDK is broken but I’m sure there is some logic here. This bug was reported to Node (since it breaks Node’s support of Android) but they responded that this is an NDK issue so Google should deal with it. But if we want to build we have to get connected to a version of Python that does support bz2. That’s what we did above. We linked the main version of Python (which any sane Linux distro will use) with the NDK so it will use that and hence support bz2.
- Now go to ~/node and issue ’make’
The actual instructions from the checkin say to run ’make -j8’ which enables parallel capabilities in Make. Apparently the rule of thumb is to set the value after j to 2x the number of hardware threads available on the machine.
Using Node.js on Android via ADB
Eventually I’ll write up an AAR that just wraps all the Node stuff and provides a standard API for launching node and feeding it a script. But that isn’t my current priority so instead I need to just get node onto my device and play with it.
- Issue the command “adb push ~/node/out/Release /data/local/tmp/Release”
- There is a step I’m skipping here. I actually do my development on Windows. So I copy the Release folder from my Linux VM (via Virtualbox) and then use the linked drive to move it to my Windows box. So in fact my adb push command above isn’t from the Linux location but my Windows location.
- The out/Release folder contains all the build artifacts for Node. Of this mess I suspect only the node executable is actually needed. But for the moment I’m going to play it safe and just move everything over.
- The reason for putting the node materials into /data/local/tmp/Release is because /data/local/tmp is one of the few areas where we can execute the chmod command in the next step and make Node executable. But when we wrap this thing up in an AAR we can actually use the setExecutable function instead.
- Issue “adb shell”. Once in the shell issue “chmod 700 /data/local/tmp/Release/node”
- I then issued an ’adb push’ for a simple hello world node program I have that I put inside of /data/local/tmp
- I used “Hello HTTP” from http://howtonode.org/hello-node
- Then I went in via “adb shell” and ran “/data/local/tmp/Release/node helloworld.js”
- And yes, it worked! I even tested it by going to the browser on the phone and navigating to http://localhost:8000.
- To kill things I just ctrl-c which does kill the adb shell but also the node app. Good enough for now.
What about NPM?
In theory one should be able to use NPM on the Linux box and then just move the whole thing over to Android and run it there. But this only works if none of the dependencies use an add-on. An add-on requires compiling C code into a form Android can handle. It looks like NPM wants to support making this happen but so far I haven’t found the right voodoo. So I’m still investigating.