QuickJS 是一个小型并且可嵌入的 Javascript 引擎,它支持ES2020规范,包括模块,异步生成器和代理器。编译下来只有几百KB,相比 V8 需要几MB小得多,在对大小有要求的嵌入式设备来说是 V8 一个不错的替代品。国人写了一份中文文档可以参考。
在Mac OS编译QuickJS
# 下载代码
git clone https://github.com/bellard/quickjs
cd quickjs
# 编译
make
执行完 make 后,就会在根目录生成了qjs
可执行文件,就可以进行测试
./qjs examples/hello.js
对象介绍
- JSRuntime:JavaScript 的运行时,可以创建多个运行时,但是不同的运行时不能共享对象。
- JSContext:一个 JSRuntime 可以创建多个 JSContext,同一个 JSRuntime 下的 JSContext 可以共享对象。
- JSValue:JavaScript 的变量及 Function 等。
在Android编译QuickJS
创建JNI项目
这一步就不介绍了,自行使用Android Studio创建一个JNI的项目。
由于QuickJS使用了一些高版本的API,所以 minSdkVersion 必须大于18。
把QuickJS代码放到项目中
需要把QuickJS 的代码下载到main/cpp/quickjs。
文件结构如下:
main
├── AndroidManifest.xml
├── cpp
│ ├── CMakeLists.txt
│ ├── quickjs-jni.cpp
│ └── quickjs
│ ├── CMakeLists.txt
│ └── quickjs
│ ├── VERSION
│ ├── cutils.c
│ ├── cutils.h
│ ├── libbf.c
│ ├── libbf.h
│ ├── libregexp.c
│ ├── libregexp.h
│ ├── libunicode.c
│ ├── libunicode.h
│ ├── quickjs.c
│ └── quickjs.h
└── java
└── com/quickjs/android/QuickJS.java
在 quickjs 目录下创建一个CMakeLists.txt文件,文件内容如下:
cmake_minimum_required(VERSION 3.10.2)
project(quickjs CXX)
include_directories(quickjs)
set(SOURCE_DIR
quickjs/cutils.c
quickjs/libbf.c
quickjs/libregexp.c
quickjs/libunicode.c
quickjs/quickjs.c
)
file(STRINGS "quickjs/VERSION" CONFIG_VERSION)
add_definitions(-DCONFIG_VERSION="${CONFIG_VERSION}")
add_definitions(-DCONFIG_BIGNUM)
add_definitions(-D_GNU_SOURCE)
add_definitions(-DCONFIG_CC="gcc")
add_definitions(-DCONFIG_PREFIX="/usr/local")
add_library(
${PROJECT_NAME}
SHARED
${SOURCE_DIR}
)
target_include_directories(${PROJECT_NAME} PUBLIC .)
把cpp/CMakeLists.txt修改成
cmake_minimum_required(VERSION 3.10.2)
project("quickjs-android")
add_subdirectory(./quickjs)
add_library(
${PROJECT_NAME}
SHARED
quickjs-jni.cpp)
find_library(
log-lib
log)
target_link_libraries(
${PROJECT_NAME}
${log-lib}
quickjs
)
QuickJS.java内容如下:
package com.quickjs.android;
public class QuickJS {
public static native int executeIntegerScript(String source,String fileName);
}
quickjs-jni.cpp 内容如下:
#include <jni.h>
#include <string>
#include <quickjs/quickjs.h>
extern "C"
JNIEXPORT jint JNICALL
Java_com_quickjs_android_QuickJS_executeIntegerScript(JNIEnv *env, jclass clazz, jstring jCode,
jstring jFileName) {
JSRuntime *jsRuntime = JS_NewRuntime();
JSContext *context = JS_NewContext(jsRuntime);
const char *code = env->GetStringUTFChars(jCode, NULL);
const int code_length = env->GetStringUTFLength(jCode);
const char *file_name = env->GetStringUTFChars(jFileName, NULL);
int flags = 0;
JSValue val = JS_Eval(context, code, (size_t) code_length, file_name, flags);
int result = JS_VALUE_GET_INT(val);
return result;
}
测试
protected void test() {
int result = QuickJS.executeIntegerScript("var a = 2+2;\n a;", "file.js");
Log.e("quickjs", String.valueOf(result));
}
static {
System.loadLibrary("quickjs");
System.loadLibrary("quickjs-android");
}
就会输出结果:4
项目代码
https://github.com/taoweiji/quickjs-android
总结
编译下来armeabi-v7a的so文件仅仅380KB,相比Google V8引擎的7MB小得多。上面只是简单的示例,需要完整使用 QuickJS 功能还需要大量的适配工作,推荐使用 quickjs-android 。