AndroidはWebViewなしでV8を利用する 質問する

AndroidはWebViewなしでV8を利用する 質問する

私は Java から JavaScript を実行する練習をしています。Rhino はデスクトップではこのために非常にうまく動作しますが、Android では (遅い) 解釈モードにフォールバックする必要があります (Rhino JIT がコンパイルする Java バイトコードを dalvik が実行できないため)。

Android には、JNI 経由で内部的にアクセスされる V8 JavaScript エンジンが組み込まれており、Rhino よりもはるかに優れたパフォーマンスを発揮するはずです。ただし、私が見つけた唯一のアクセス方法は、WebView 経由で間接的にアクセスすることです。

残念ながら、WebView にはコンテキストが必要で、null コンテキストでは NPE でクラッシュするため、ダミーの WebView をインスタンス化してコードを実行し、結果を返すことすらできません。私の演習の性質上、WebView にコンテキストを提供することは実際にはできないので、何か見落としていることがあるのではないかと期待しています。

これらの 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+")");
    }
}

理想的には、V8 を直接呼び出すか、少なくとも実際の WebView を必要とせずに JavaScript を実行するためのサポートされている方法が必要です。JavaScript コードを実行するだけの場合、かなり扱いにくく複雑な方法に思えるからです。

アップデート

コードを少し再配置しましたが、ここでは見えませんが、AsyncTasks の onPreExecute() で V8Threads をインスタンス化し、その他すべてを doInBackground() に保持しています。ソース コードはプログラムの早い段階で読み込まれるため、スレッドごとに冗長に再読み込みされることはありません。

V8Thread が UI スレッドでインスタンス化されるようになったため、現在のビューのコンテキストを渡すことができます (フラグメントを使用しているため、単に「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");
    }
}

ただし、実行すると、logcat はスレッドごとに「最初のレイアウト後に viewWidth を取得できません」というエラーを 1 つ出力し、JavaScript コードは実行されません。「Here」ログ メッセージが送信されるため、スレッドが完全に起動していることはわかります。以下は、js コード内の関連する test() 関数です。

function test()
{
V8Thread.setResult("blah");
}

正しく動作している場合、「blah」は logcat に 4 回表示されるはずですが、一度も表示されません。ソース コードが誤って読み取られた可能性がありますが、それは疑わしいです。

Scanner scan = new Scanner(assetManager.open("pi.js"));
while (scan.hasNextLine()) source += scan.nextLine();

私が想像できる唯一の他のことは、前述のエラーが原因で、webView が実際には JavaScript を実行できないということです。

また、pi.js には JavaScript のみが含まれており、HTML は一切含まれていないことも付け加えておきます。ただし、Web ページとして適格となるだけの HTML でラップしても、まだうまくいきません。

ベストアンサー1

API経由で新しいV8コンテキストを作成し、それを使用してJavaScriptを実行することができます。https://android.googlesource.com/platform/external/v8 include2つのC++ヘッダーファイルを含むディレクトリ。libwebcore.so(https://android.googlesource.com/platform/external/webkit) ライブラリを NDK 経由で使用するので、特別なことは何もありません。

v8::Persistent<v8::Context> context = v8::Persistent<v8::Context>::New(v8::Context::New());
context->Enter();

参照するhttps://developers.google.com/v8/get_startedこれは Android でも動作します。デバイスに実際に V8 が搭載されていることを確認してください (一部の古いデバイスには JSC [JavaScript Core] が搭載されています)。

おすすめ記事