Используя технику, заимствованную у http://www.gutterbling.com/blog/synchronous-javascript-evaluation-in-android-webview/, мы успешно реализовали ряд функций в нашем приложении, которые позволяют нашему Android-приложению синхронно получать данные из Webview.Android Synchronous Javascript с WebView на Lollipop
Вот пример из gutterbling:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import android.content.Context;
import android.util.Log;
import android.webkit.WebView;
/**
* Provides an interface for getting synchronous javascript calls
* @author btate
*
*/
public class SynchronousJavascriptInterface {
/** The TAG for logging. */
private static final String TAG = "SynchronousJavascriptInterface";
/** The javascript interface name for adding to web view. */
private final String interfaceName = "SynchJS";
/** Countdown latch used to wait for result. */
private CountDownLatch latch = null;
/** Return value to wait for. */
private String returnValue;
/**
* Base Constructor.
*/
public SynchronousJavascriptInterface() {
}
/**
* Evaluates the expression and returns the value.
* @param webView
* @param expression
* @return
*/
public String getJSValue(WebView webView, String expression)
{
latch = new CountDownLatch(1);
String code = "javascript:window." + interfaceName + ".setValue((function(){try{return " + expression
+ "+\"\";}catch(js_eval_err){return '';}})());";
webView.loadUrl(code);
try {
// Set a 1 second timeout in case there's an error
latch.await(1, TimeUnit.SECONDS);
return returnValue;
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted", e);
}
return null;
}
/**
* Receives the value from the javascript.
* @param value
*/
public void setValue(String value)
{
returnValue = value;
try { latch.countDown(); } catch (Exception e) {}
}
/**
* Gets the interface name
* @return
*/
public String getInterfaceName(){
return this.interfaceName;
}
}
Этот JS интерфейс используется так:
WebView webView = new WebView(context);
SynchronousJavascriptInterface jsInterface = new jsInterface();
webView.addJavascriptInterface(jsInterface, jsInterface.getInterfaceName());
String jsResult = jsInterface.getJSValue(webView, "2 + 5");
Несмотря на работу хорошо в Android 4.0 - 4.4.4 это не работает для нас с Android 5.0 (Lollipop).
Похоже, что в Lollipop JS выполняется после завершения отсчета защелки, тогда как ранее он возвращал значение до завершения обратного отсчета.
Что-то изменилось с помощью потоков, которые JS в Webview выполняет? И можно ли каким-либо образом исправить это, не переписывая большие куски нашего приложения, которые зависят от возможности одновременного вызова JS?
Вы спасли мне жизнь! – maxgallo
Хм, он не работает. См. Https://code.google.com/p/android/issues/detail?id=79924 Надеюсь, он будет исправлен, но теперь нет обходного пути. Есть предположения? –
@RomanZhukov Спасибо за ссылку на эту проблему, из журнала изменений выяснилось, что эта проблема была исправлена в Android 5.1 (и в выпуске выпущенной версии Webview 40). Я не тестировал старую версию своего приложения, чтобы проверить этот факт, но будет делать так. –