Viable options for running NodeJS on Android (Aug 2017)
There are a bunch of old SO threads dealing with running NodeJS on Android. Most of these are no longer viable (JXCore) and/or provide confusing, outdated, incomplete, or erroneous information.
Therefore I have investigated what seems to be currently (as of August 2017) viable approaches and found three likely candidates.
To decide between them I would like to know:
- the primary differences between these approaches
- specific pro's and con's on each approach
- likely hurdles, challenges and shortcomings
- do you know of other viable alternatives?
Viable approaches are:
- Running V8 javascript engine which includes NodeJS (J2V8)
- Use NodeJS directly, embedded as native library (node-on-android)
- Combining React Native with NodeJS app-as-a-service (react-native-node)
Besides that I have found a number of related interesting resources:
- NPM install NodeJS directly using Termux without rooting (not for end-users)
- LiquidCore - native mobile micro-app devenv (not investigated, interesting concepts)
- dna2oslab - has a working NodeJS build script for node executables
- Building NodeJS for Android - blog with useful compilation tips and example project
Solution 1:
Investigating viable options
[NOTE This answer contains findings that were in the original question]
I have investigated the various options a bit more and here are some preliminary findings.
0. Compiling NodeJS
Each of the options uses some form of NodeJS compiled for Android. But to use any option you would probably want to compile to different Node, Android and architecture (x86, ARM, ARM64, etc.) versions.
This is problematic. NodeJS has an android-configure
script, but this results in errors in most combinations I've tried. I created a number of github issues for a working build script. In this issue results are collected:
- Working build script for Android ARM Node 7.x or 8.x shared library
To summarize:
- shared library builds all fail (except when building physically on your android, see below)
- J2V8 with NodeJS (
libnode.a
) statically linked inlibj2v8.so
works for 7.x up to7.9.0
- build-as-node-executable works for 7.x (using dna2oslab build script)
One interesting workaround was used by @mafintosh: transfer Node to device using Termux and do the compilation there (needs much space and time, but works).
1. Running V8 javascript engine which includes NodeJS (J2V8)
J2V8 is a set of Java bindings for V8. J2V8 focuses on performance and tight integration with V8. [...] [which] forces a more static type system between the JS and Java code, but it also improves the performance since intermediate Objects are not created. [...]
Building J2V8 requires building both the native parts and the Java library (.jar/.aar file). To build the native parts we first build node.js as a library and then statically link J2V8 to that. [...]
For cross-compiling J2V8 uses Docker (android, linux, windows) and Vagrant (macos).
See slideshare: Running NodeJS in a Java World (or see InfoQ video, 32min.)
Features:
- replace JavaScriptCore engine with more powerful v8 (with NodeJS)
- multi-threading (threads/workers) support via added J2V8 JNI / Java layer
- every thread can have its own Isolated V8 Instance
- 2-way js-to-java bridge (call java from script and vice versa)
- 2-way integrated error / exception handling
- beautiful cross-compiling interactive build system (in the works)
- chrome debugging support
- others, typed arrays, ES6 support, ...
Characteristics:
- Specify the versions to compile in
build_system/build_settings.py
-
Start a build simply with
python build.py --interactive
, select build:[0] Docker >> android-x86 >> NODE_ENABLED [1] Docker >> android-arm >> NODE_ENABLED [2] Docker >> alpine-linux-x64 >> NODE_ENABLED [3] Docker >> linux-x64 >> NODE_ENABLED [4] Docker >> linux-x86 >> NODE_ENABLED [5] Vagrant >> macosx-x64 >> NODE_ENABLED [6] Vagrant >> macosx-x86 >> NODE_ENABLED [7] Native >> windows-x64 >> NODE_ENABLED [8] Docker >> windows-x64 >> NODE_ENABLED [9] Vagrant >> windows-x64 >> NODE_ENABLED
-
Select build steps (or
all
):NodeJS --> CMake --> JNI --> Optimize --> Java/Android --> JUnit
-
Compiles V8 as shared library
libj2v8_{platform}_{abi}.{ext}
-
Note:
nodejs
build step cannot build Node shared library (errors), creates staticlibnode.a
to be linked inlibj2v8.so
-
Note:
- Has a JNI layer to make large parts of v8 accessible by Java
- Additional features (e.g. JS <--> Java bridge) implemented in Java
- Final build output is a Gradle
.aar
to include as project dependency
Pros:
- Relatively active project
- Good quality code including Java unit tests
- Adds full power of Java to your app design toolkit
- Great, intuitive build system (once finished)
Cons:
- Little, mostly outdated usage documentation
- Especially undocumented is usage in large(r)-scale JS projects
- Lot of JNI glue code that must be maintained
- Project not well-maintained (many old open issues, non-merged PR's)
- Some PR's hang around for 2 years without even getting a response. Not good
- Harder to understand J2V8 project setup (many files) than other options
- Licensing issue ("All rights reserved" in EPL 1.0 license)
2. Use NodeJS directly, embedded as native library (node-on-android)
Node on android works by running your Node.js inside the android app using a shared library. It then bundles a
WebView
that hosts your UI code. All UI is just classic html/css/js.In the node app you can require
node-on-android
to get access to the WebView. You can use this to load an html page in theWebView
.
According to node-on-android
creator (@mafintosh) this is easier and better than J2V8 as it compiles V8 directly as the real thing.
Features:
- Build full-fledged NodeJS applications, including UI (via native WebView)
Characteristics:
- Relevant directories / files in gradle
app
project:-
app/src/main/include/node
with node.h
headers -
app/src/main/jniLibs/arm64-v8a
withlibc++_shared.so
andlibnode.so
-
app/src/main/cpp
withnative-lib.cpp
(includesnode.h
) - Java code, just spins up a
Service
with node running in a separate thread
-
- Has no JNI for
libnode.so
, soprivate native void startNode(String... app);
shows as error in IDE (but compiles) - The NodeJS project resides in
android/app/src/main/assets/node
- NodeJS code is transferred to temporary storage and executed from there
- NodeJS app specifies views to load in WebView via exposed
loadUrl
function- Node service accessible via NPM package
node-on-android
- Node service accessible via NPM package
Pros:
- Simple project, not much plumbing code
- Comes with a recent v8.x Node version out-of-the-box
- Simple HTML-based app UI programming (e.g. using choo)
- Works out-of-the-box :)
Cons:
- Very new project, only experimental code still
- Comes just for
arm64
architecture (full mobile support planned, or DIY build)- Note: 64-bit cannot be combined with React Native (no 64-bit support)!
- No native UI possible (unless coding in Gradle/Java/XML)
- No debugging support on Node app (AFAIK, but maybe you can attach to the WebView somehow)
3. Combining React Native with NodeJS app-as-a-service (react-native-node)
Run a real Node.js process in the background, behind a React Native app.
Using this package you can: run http servers in Android, use Node streams, interface with the filesystem, offload some heavy processing out of the JS thread in React Native, and more! Running the real Node.js in Android, you can do everything that Node.js on desktop can.
Features:
- Use React Native for the UI, NodeJS as a background service
Characteristics:
- Derived from NodeBase
- Very similar to node-on-android (run
Service
with Node on separate thread)- But
node
is compiled/used as application, not an embedded shared lib - NodeJS app code is located in
{projectRoot}/background
- NodeJS executable is in
/android/src/main/res/raw/bin_node_v710
- At build time Node app is tarballed, unpacked at `/android/src/main/res/raw/{appName}
- NodeJS service is invoked as if run from the command-line, passing args
- But
- Node service
RNNode
is available in RN by importingreact-native-node
-
react-native-node
also contains CLI that transfers Node code at build time
-
- The Example project communicates from React Native to NodeJS service via REST
- Running an
express
server onhttp://localhost:5000
at Node side
- Running an
Pros:
- Simple project, not much plumbing code
- Obvious: React Native support with NodeJS on android!
- Node-as-executable will probably work with 64-bit devices + react-native
Cons:
- Very new project, only experimental code still
- Comes with old NodeJS
7.1.0
version (but DIY build newer ones) - No easy way to communicate between RN and Node apps (REST-based)
- Need to extend REST API or roll your own mechanism
- No debugging support on Node app. Really hard to know what's going on
Status (2017-08-17)
My goal is React Native + NodeJS. This is the status of my activities:
- Compiling NodeJS v7.x versions as executable works
- Compiling NodeJS v7.4.0 up to v7.9.0 works with new J2V8 build system
- Compiling NodeJS v8.1.2 will soon work with J2v8 (compiled against
libc++
) -
react-native-node
does compile, but does not operate despite many tries -
node-on-android
works, but node-only app development and 64-bit incompatible with RN
I decided to combine react-native-node
with J2V8
because of:
- Great cross-compile build PR: https://github.com/eclipsesource/J2V8/pull/327
- Builds into a nice J2V8
.aar
to be easily included in Gradle
React Native 0.46.4
+ NodeJS 7.9.0
is now working! See:
- https://github.com/staltz/react-native-node/issues/5#issuecomment-323049897
My use case: fat client with P2P decentralized networking
I am thinking of a CQRS (command-query-responsibility-segregation) design:
- react-native UI is constructed from view queried from the node service
- react-native UI actions trigger commands on the node background service
- background service processes network messages, incoming commands, triggers events
- events are stored in Realm DB that forms the bridge between front and back
Details: Realm.io to bridge native NodeJS + React Native in Android fat client app (CQRS-style)
Conclusion
Even after years of people trying to port NodeJS to Android there are still no real good solutions, it is pioneering.
Expect many hurdles and errors as you set up your project and build environment, but once setup you could enjoy the full power of Node on your phone.
Solution 2:
As of today (March 2018), there is another viable alternative not yet listed in the current answers: Node.js for Mobile Apps.
At its core, the project provides a native library for embedding Node.js into native Android and iOS applications; but it also comes with plugins for React Native and Cordova.
Pre-built binaries for the library are available for Android armeabi-v7a, x86, arm64-v8a, x86_64, and for iOS 64-bit.
The core library is a fork of nodejs/node-chakracore, which in turn is fork of nodejs/node. The Android version is pretty much regular Node.js built as a library, with a few portability fixes. The iOS version uses the ChakraCore engine instead of V8 (replacing V8 with ChakraCore is possible thanks to the changes in the nodejs/node-chakracore fork).
The React Native and Cordova plugins make it easier to add Node.js to applications built using those frameworks. The Node.js code runs in a separate engine and thread than the framework's (React Native / Cordova). Communication between the two JavaScript worlds is achieved via a messaging bridge provided by the plugins.
More information, including some documentation, is available on the project website.
(Full disclosure: I work for the company that develops Node.js for Mobile Apps.)
Solution 3:
I am the author of LiquidCore. LiquidCore allows you to use full implementations of Node.js on both Android and iOS (iOS support was just released in version 0.5.0 -- September 2018).
LiquidCore is designed to enable multiple instances of Node to run simultaneously inside of a native mobile app. Each instance has its own virtual file system and native support for MySQL. The goal of the project is to enable full "micro apps" to be built using JavaScript/WebAssembly that can then be embedded into other apps, and I am still working toward that goal. But as of today, it works great if you just want a Node.js playground.
If you want to see what it can do, there is a simple node console app included for both Android and iOS.