Android использует V8 без WebView

Я выполняю javascript с Java. Rhino работает очень хорошо для этого на рабочем столе, но должен вернуться к (медленному) интерпретируемому режиму на Android (из-за того, что dalvik не может выполнить байт-код Java, составленный Rhino JIT).

Android имеет встроенный движок JavaScript V8, доступ к которому осуществляется через JNI, и он должен обеспечивать гораздо лучшую производительность, чем Rhino; Однако единственный способ найти доступ к нему – косвенно через WebView.

К сожалению, WebView требует контекста и сбой с NPE с нулевым контекстом, поэтому я не могу даже создать экземпляр фиктивного WebView, чтобы просто выполнить код и вернуть результат. Природа моего упражнения на самом деле не позволяет мне предоставить контекст для WebView, поэтому я надеюсь, что, возможно, я кое-что упускаю из виду.

Некоторые из этих V8Threads работают параллельно, поэтому, насколько мне известно, не реально (насколько мне известно) добавить 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 или, по крайней мере, выполнить javascript, не требуя фактического WebView, поскольку он выглядит довольно неуклюжим и запутанным методом для запуска javascript-кода.

ОБНОВИТЬ

Я немного изменил свой код, хотя неясно, что теперь я создаю экземпляр V8Threads в onPreExecute () AsyncTasks, сохраняя все остальное в doInBackground (). Исходный код читается ранее в программе, поэтому он не избыточно перечитывается для каждого потока.

Поскольку теперь V8Thread создается в потоке пользовательского интерфейса, я могу передать ему контекст текущего представления (я использую фрагменты, поэтому я не могу просто передать это «это»), поэтому он больше не сработает.

 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 вырывает по одному на поток ошибки «Невозможно получить вид ширины после первого макета», а код javascript никогда не выполняется. Я знаю, что поток полностью срабатывает, потому что отправляется сообщение журнала «Здесь». Вот соответствующая функция test () в js-коде.

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

Правильно работая, «бла» должен появляться четыре раза в logcat, но он никогда не появляется. Может быть, мой исходный код читается неправильно, но я в этом сомневаюсь.

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

Единственное, что я могу себе представить, это то, что из-за этих вышеупомянутых ошибок webView никогда не сталкивается с выполнением javascript.

Я также добавлю, что pi.js содержит только javascript, без HTML. Тем не менее, даже когда я обертываю его достаточно HTML, чтобы он квалифицировался как веб-страница, до сих пор не повезло.

Вы можете создать новый контекст V8 через свой API и использовать его для выполнения JavaScript, посмотрите в https://android.googlesource.com/platform/external/v8 include каталог, который содержит два файла заголовков 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 (некоторые более старые устройства поставляются с АО [JavaScript Core]).

Я нашел этот отличный отличный исходный код, совместимый с ECMAScript, JS Engine, полностью написанный на C под названием duktape

Duktape – это встраиваемый механизм Javascript, ориентированный на мобильность и компактность.

Вам все равно придется заниматься бизнесом ndk-jni, но это довольно прямолинейно. Просто duktape.c и duktape.h из дистрибутивного источника здесь (если вы не хотите самостоятельно проходить процесс сборки) в папку jni, обновите Android.mk и все такое.

Вот пример фрагмента С, чтобы вы начали.

 #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; } 

Удачи!

Немного позднего ответа, но это может быть полезно любому, кто споткнется на этот вопрос. Я использовал библиотеку J2V8, которая является оболочкой Java в Google V8. Эта библиотека поставляется с предварительно скомпилированными двоичными файлами V8 для Android-устройств x86 и armv7l. Он работает без проблем. См. Здесь для учебных пособий. Просто держите в середине, так как чистый V8 – всего лишь механизм Ecmascript, нет элемента DOM.

Можете ли вы завладеть Context который является вашим Application ? Есть несколько способов сделать это.

  1. Вызовите getApplication () из своей Activity ( Application является дочерним элементом Context )
  2. Вызовите getApplicationContent () из Context ( Context вероятно, являющийся вашей Activity )

ОБНОВИТЬ

Согласно этой документации для Android , ваш связанный код Javascript будет работать в отдельном процессе, так что не нужно настраивать его в своем Thread .

По ссылке:

Примечание. Объект, привязанный к вашему JavaScript, выполняется в другом потоке, а не в потоке, в котором он был создан. («Объект» относится к классу JavascriptInterface)

Вы можете использовать проект Android . Он не основан на V8, но JavaScriptCore. Текущая версия (2.2+) поддерживает компиляцию JIT для всех процессоров, не названных MIPS.