私は 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 include
2つの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] が搭載されています)。