Use V8 JavaScript engine to execute JS lib without

2019-01-13 22:19发布

问题:

I am developing a JavaScript component which is responsible for making requests to the server and dispatching results to the UI. By doing this in JavaScript, I am able to use my component in several types of UI: Android app, iOS app, desktop app (QT), web app...

All these UI have instantiated a web view, so my component is started when the UI loads the dedicated URL (webview.load("file://myfirstWebPage.html")).

This first web page loads all the JavaScript components, and when it's done, the UI is able to make some requests to the JavaScript component, which makes a request to the server and when it has the response, it dispatches it back to the client (UI Android, UI iOS ...)

This architecture works fine, but I would like to know if there is another way to load the JavaScript component without using a web view on each client?

Can the V8 engine help me?

回答1:

If I'm understanding your question, you're looking for a way to execute JavaScript across many platforms (iOS, Android, etc.) without the use of a WebView. The solution will be platform-specific, since even the underlying WebView implementations are different for each platform.

For Android, so long as the device ships with V8, you can create a new V8 Context via its API and use that to execute your JavaScript. The device must actually ship with V8. This answer may help you further.

For iOS, which uses JavaScriptCore, recent developments in iOS7 have been made to allow you load and run arbitrary JavaScript code. Read more here.



回答2:

I don't know how to use V8, but you can use Rhino library instead. There is no WebView involved too.

Download Rhino first, unzip it, put the js.jar file under libs folder. It is very small, so you don't need to worry your apk file will be ridiculously large because of this one external jar.

Here is some simple code to execute JavaScript code.

Object[] params = new Object[] { "javaScriptParam" };

// Every Rhino VM begins with the enter()
// This Context is not Android's Context
Context rhino = Context.enter();

// Turn off optimization to make Rhino Android compatible
rhino.setOptimizationLevel(-1);
try {
    Scriptable scope = rhino.initStandardObjects();

    // Note the forth argument is 1, which means the JavaScript source has
    // been compressed to only one line using something like YUI
    rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);

    // Get the functionName defined in JavaScriptCode
    Object obj = scope.get(functionNameInJavaScriptCode, scope);

    if (obj instanceof Function) {
        Function jsFunction = (Function) obj;

        // Call the function with params
        Object jsResult = jsFunction.call(rhino, scope, scope, params);
        // Parse the jsResult object to a String
        String result = Context.toString(jsResult);
    }
} finally {
    Context.exit();
}

You can see more details at my post.



回答3:

For the Android part. I used J2V8 JavaScript library. It is a Java wrapper of Google's V8 JavaScript engine. See here for more details.



回答4:

I found this really nifty open source ECMAScript compliant JS Engine completely written in C called duktape

Duktape is an embeddable Javascript engine, with a focus on portability and compact footprint.

You'd still have to go through the ndk-jni business, but it's pretty straight forward. Just include the duktape.c and duktape.h from the distributable source here(If you don't want to go through the build process yourself) into the jni folder, update the Android.mk and all that stuff.

Here's a sample C snippet to get you started.

#include "duktape.h"

JNIEXPORT jstring JNICALL
Java_com_ndktest_MainActivity_evalJS
(JNIEnv * env, jobject obj, jstring input){
    duk_context *ctx = duk_create_heap_default();
    const char *nativeString = (*env)->GetStringUTFChars(env, input, 0);
    duk_push_string(ctx, nativeString);
    duk_eval(ctx);
    (*env)->ReleaseStringUTFChars(env, input, nativeString);
    jstring result = (*env)->NewStringUTF(env, duk_to_string(ctx, -1));
    duk_destroy_heap(ctx);
    return result;
}

Good luck!