QuickJS 是一個小型并且可嵌入的 Javascript 引擎,它支持ES2020規(guī)范,包括模塊,異步生成器和代理器。編譯下來只有幾百KB,相比 V8 需要幾MB小得多,在對大小有要求的嵌入式設(shè)備來說是 V8 一個不錯的替代品。國人寫了一份中文文檔可以參考。
在Mac OS編譯QuickJS
# 下載代碼
git clone https://github.com/bellard/quickjs
cd quickjs
# 編譯
make
執(zhí)行完 make 后,就會在根目錄生成了qjs可執(zhí)行文件,就可以進(jìn)行測試
./qjs examples/hello.js
對象介紹
- JSRuntime:JavaScript 的運(yùn)行時,可以創(chuàng)建多個運(yùn)行時,但是不同的運(yùn)行時不能共享對象。
- JSContext:一個 JSRuntime 可以創(chuàng)建多個 JSContext,同一個 JSRuntime 下的 JSContext 可以共享對象。
- JSValue:JavaScript 的變量及 Function 等。
在Android編譯QuickJS
創(chuàng)建JNI項目
這一步就不介紹了,自行使用Android Studio創(chuàng)建一個JNI的項目。
由于QuickJS使用了一些高版本的API,所以 minSdkVersion 必須大于18。
把QuickJS代碼放到項目中
需要把QuickJS 的代碼下載到main/cpp/quickjs。
文件結(jié)構(gòu)如下:
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 目錄下創(chuàng)建一個CMakeLists.txt文件,文件內(nèi)容如下:
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內(nèi)容如下:
package com.quickjs.android;
public class QuickJS {
public static native int executeIntegerScript(String source,String fileName);
}
quickjs-jni.cpp 內(nèi)容如下:
#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");
}
就會輸出結(jié)果:4
項目代碼
https://github.com/taoweiji/quickjs-android
總結(jié)
編譯下來armeabi-v7a的so文件僅僅380KB,相比Google V8引擎的7MB小得多。上面只是簡單的示例,需要完整使用 QuickJS 功能還需要大量的適配工作,推薦使用 quickjs-android 。