Example Android Studio project that embeds v8 (plus some notes on compiling v8 for android)
The intention is to embed v8 inside an Android app, and this project is an example of getting "Hello World" from Javascript to show up on the Android app (using v8).
Note: If you're building a production/real-world Android app, I recommend you use J2V8 instead (unless you need to make 100s of calls/sec between JS and the runtime, in which case you should use this project's approach to avoid the JNI overhead in J2V8). This project is a learning exercise, or a starting point to start a v8 binding from scratch, for higher raw performance.
I needed it for building an Android game, which used Javascript as a scripting language for modding. Other engines weren't performant-enough or embeddable. Your uses may vary.
I'm sure there is room to reduce the binary size and improve things. I followed ibon's excellent guide, but needed to change a few things to make it work with recent changes (hence this doc).
Install the jni-test.apk file (~7mb) incase you only want to see it running. This apk has only been compiled for armeabi-v7a, so let me know if it doesn't work on your phone
- Clone this repository, and open the
jni-test
directory as a project in your Android Studio. - Run the project after connecting your phone via USB.
Incase it has issues, try renaming the app/libs/armeabi-v7a
directory to your phone's ABI format, like app/libs/arm64-v8a
and update the ABI filter in build.grade with your device's ABI format. Or maybe just edit the app/CMakeLists.txt
file and remove the ${ANDROID_ABI}
parameter. Confirm your device's ABI (via Google?).
This uses a prebuilt v8 library for Android, compiled from version 7.2.502.24 of v8 (released Jan 24, 2019). You may want to create a new binary, with the latest v8 changes.
- The compiled APK file, if you want to try: jni-test.apk (~7mb)
- The CMakeLists.txt for linking the v8 libraries
- The native-lib.cc C++ file that contains a 'Hello World' v8 program, and gets called by MyActivity.java
- The v8 library binary compiled for Android from version 7.2.502.24 (released Jan 24, 2019): libv8.a.
- Compile v8 for android_arm target
- Manually generate the ".a" static libraries from the ".o" files using the 'ar' command. The build-generated versions weren't working for some reason.
- Create an Android NDK project from Android Studio.
- Copy the
include
directory from v8, and the static libraries created previously and paste into an Android project'sapp/libs/armeabi-v7a/
directory. - Specify these libraries and include directory path in the Android project's
CMakesLists.txt
file. - Use v8 in the native C++ file, which gets called from the Java Android Activity via JNI.
Tip: Before compiling your own v8, check other repositories like ejecta-v8 if they have already compiled a new v8 version (and remember to copy the include
folder as well!).
- Build on Ubuntu (or some Linux with ELF and glibc). I was on a Mac, so I created a Virtual Machine and used Ubuntu Server for a minimal distro. Give it atleast 40 GB of disk (can use dynamic resize).
- Follow https://github.com/v8/v8/wiki/Building-from-Source
- But before running
v8gen.py
, first runecho "target_os = ['android']" >> /path/to/workingDir/.gclient && gclient sync
- Then run
tools/dev/v8gen.py gen -m client.v8.ports -b "V8 Android Arm - builder" android_arm.release
- Next, run
gn args out.gn/android_arm.release
and use these flags:
is_component_build = false
is_debug = false
symbol_level = 1
target_cpu = "arm"
target_os = "android"
use_goma = false
v8_android_log_stdout = true
v8_static_library = true
use_custom_libcxx = false
use_custom_libcxx_for_host = false
v8_use_external_startup_data = false
- Next, run
ninja -C out.gn/android_arm.release
- Then create the
libv8_base.a
andlibv8_snapshot.a
static libraries manually (the built ones don't seem to work for some reason):
mkdir libs
cd libs
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/v8_base/*.o
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/v8_libbase/*.o
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/v8_libsampler/*.o
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/v8_libplatform/*.o
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/src/inspector/inspector/*.o
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/third_party/icu/icuuc/*.o
ar -rcsD libv8_base.a /path/to/v8/out.gn/android_arm.release/obj/third_party/icu/icui18n/*.o
ar -rcsD libv8_snapshot.a /path/to/v8/out.gn/android_arm.release/obj/v8_snapshot/*.o
- Then copy the includes using
cp -R /path/to/v8/include .
- Now you can use these in your Android NDK project
- Either create a new Android NDK project in your Android Studio, or use one that's already set up with CMake
- Copy the
include
directory from v8, and the static libraries created previously and paste into an Android project'sapp/libs/armeabi-v7a/
directory. - Specify these libraries and include directory path in the Android project's
CMakesLists.txt
file. - Use v8 in the native C++ file, which gets called from the Java Android Activity via JNI.
Use the example project for the example CMakeLists.txt
and C++ file.
The key gotcha was that the .a
files created by the build didn't seem to work for some reason, or maybe I was messing the order. So what worked was manually combining the relevant .o
files (base, libbase, platform, sampler, inspector, icui18n, icuuc) into libv8_base.a, and the v8_snapshot .o
files into libv8_snapshot.a.
Then the order in CMakeList was important: v8_base followed by v8_snapshot.
Another thing to remember: the v8 compilation process will probably take 30 GB of disk space, and download probably 15 GB of stuff. This could be because it downloaded stuff a few times, mostly because of my sheer incompetence at compiling v8. But size your VM disk, time and patience accordingly.