Android使用V8而不使用WebView

Uej*_*jji 45 javascript android v8

我正在练习从Java执行javascript.Rhino在桌面上运行得非常好,但是必须回到Android上的(缓慢)解释模式(由于dalvik无法执行Rhino JIT编译的Java字节码).

Android有内置的V8 javascript引擎,通过JNI内部访问,应该提供比Rhino更好的性能; 但是,我能找到访问它的唯一方法是间接通过WebView.

不幸的是,WebView需要一个Context,并且与NPE一起使用空上下文崩溃,所以我甚至无法实例化一个虚拟WebView来执行代码并返回结果.我的练习的本质并不能让我为WebView提供一个Context,所以我希望也许有些东西我会忽略.

其中有几个V8Thread并行运行,所以我的布局中添加一个WebView并隐藏它并不是真的可行(据我所知),因为我不相信单个WebView可以在多个线程中执行函数.

private class V8Thread extends Thread
{
    private WebView webView;
    private String source;

    private double pi;
    private int i, j;

    public V8Thread(int i, int j)
    {
        pi = 0.0;
        this.i = i;
        this.j = j;

        source = "";

        try {
            InputStreamReader isReader = new InputStreamReader(assetManager.open("pi.js"));
            int blah = isReader.read();
            while (blah != -1)
            {
                source += (char)blah;
                blah = isReader.read();
            }

            webView = new WebView(null);
            webView.loadData(source, "text/html", "utf-8");
            webView.getSettings().setJavaScriptEnabled(true);
            webView.addJavascriptInterface(this, "V8Thread");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public double getResult()
    {
        return pi;
    }

    @Override
    public void run() 
    {
        webView.loadUrl("javascript:Androidpicalc("+i+","+j+")");
    }
}
Run Code Online (Sandbox Code Playgroud)

理想情况下,必须有一些支持的方式直接调用V8,或者至少执行javascript而不需要实际的WebView,因为它似乎是一个相当笨重和复杂的方法来运行javascript代码.

UPDATE

我已经重新安排了我的代码,虽然这里看不见的是现在我在AsyncTasks的onPreExecute()上实例化V8Threads,同时保留doInBackground()中的所有其他内容.源代码在程序的早期读入,因此不会为每个线程重复读取.

因为现在V8Thread在UI线程上实例化,我可以传递它当前视图的Context(我使用片段所以我不能只是将它传递给"this"),所以它不再崩溃.

private class V8Thread extends Thread
{
    private WebView webView;

    private double pi;
    private int i, j;

    public V8Thread(int i, int j)
    {
        pi = 0.0;
        this.i = i;
        this.j = j;

        source = "";

        webView = new WebView(v.getContext());
    }

    @SuppressWarnings("unused")
    public void setResult(String in)
    {
        Log.d("Pi",in);
    }

    public double getResult()
    {
        return pi;
    }

    @Override
    public void run()
    {
        webView.getSettings().setJavaScriptEnabled(true);
        webView.addJavascriptInterface(this, "V8Thread");
        webView.loadData(source, "text/html", "utf-8");
        //webView.loadUrl("javascript:Androidpicalc("+i+","+j+")");
        webView.loadUrl("javascript:test()");
        Log.d("V8Thread","Here");
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,在执行时,logcat会在错误的每个线程中吐出一个"在第一个布局后无法获取viewWidth"并且javascript代码永远不会执行.我知道线程完全触发,因为发送了"Here"日志消息.这是js代码中的相关test()函数.

function test()
{
V8Thread.setResult("blah");
}
Run Code Online (Sandbox Code Playgroud)

工作正常,"blah"应该在logcat中出现四次,但它永远不会显示出来.可能是我的源代码读错了,但我怀疑.

Scanner scan = new Scanner(assetManager.open("pi.js"));
while (scan.hasNextLine()) source += scan.nextLine();
Run Code Online (Sandbox Code Playgroud)

我唯一可以想象的是,由于上述错误,webView实际上从未实际执行过javascript.

我还要补充一点,pi.js只包含javascript,不包含任何HTML.但是,即使我用足够的HTML包装它以使其有资格作为网页,仍然没有运气.

sou*_*kah 10

您可以通过其API创建一个新的V8上下文并使用它来执行您的JavaScript,查看包含两个C++头文件的https://android.googlesource.com/platform/external/v8 include目录.通过NDK 链接libwebcore.so(从https://android.googlesource.com/platform/external/webkit编译)库,没什么特别的.

v8::Persistent<v8::Context> context = v8::Persistent<v8::Context>::New(v8::Context::New());
context->Enter();
Run Code Online (Sandbox Code Playgroud)

请参阅适用于Android的https://developers.google.com/v8/get_started.只需确保该设备实际上附带V8(一些旧设备附带JSC [JavaScript Core]).

  • 您是否建议我们编译V8并将其包含在应用程序中?我在互联网上的任何地方都没有看到关于如何链接和使用设备的V8安装的文档.你说这没什么特别的,但我不知道从哪里开始......:/ (2认同)
  • V8已经在libwebcore.so中可用,只需从您的NDK代码中使用它. (2认同)
  • 当我尝试加载库时,通过:`static{ System.loadLibrary("webcore"); }` 我得到一个 UnsatisfiedLinkError 有没有人通过这里完成的操作成功加载了库:[WebViewCore](https://www.gitorious.org/rf4ceandroid/frameworks_base/source/690b964c5dc29608b336b2464ba123bcef9d9edf:core/java/androidViewCore.webViewCore/ java“WebViewCore”) (2认同)
  • 这真的是呼吁一个工作的Github示例应用程序来做到这一点.是否可以通过仅包含一个微小的存根代码而不是相当大的完整v8二进制文件来使用v8 javascript引擎? (2认同)

Ang*_*elo 5

有点迟到的反应但对任何绊倒这个问题的人都有用.我使用了J2V8库,它是Google V8引擎上的Java包装器.该库附带了针对x86和armv7l Android设备的预编译V8二进制文件.它无缝地工作.请参阅此处获取教程.只是保持在中间,因为纯V8只是一个Ecmascript引擎,没有可用的DOM元素.


nic*_*ild 1

你能抓住属于Context你的Application吗?有几种方法可以做到这一点。

  1. 从您的(是 的子级)调用getApplication()ActivityApplicationContext
  2. 从(可能是您的)调用getApplicationContent()ContextContextActivity

更新

根据这个Android 文档,您绑定的 Javascript 代码无论如何都会在单独的进程中运行,因此不需要在自己的进程中进行设置Thread

从链接:

注意:绑定到 JavaScript 的对象在另一个线程中运行,而不是在构造它的线程中运行。(所指的“对象”是 JavascriptInterface 类)