2014-10-28 2 views
2

Используя технику, заимствованную у 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?

ответ

6
loadUrl("javascript:" + code) 

не работают с API> 19, вместо этого использовать:

evaluateJavascript(code, null); 

Или, вы можете улучшить свой код, чтобы использовать функцию обратного вызова, предоставленную evaluateJavascript, хотя.

+1

Вы спасли мне жизнь! – maxgallo

+1

Хм, он не работает. См. Https://code.google.com/p/android/issues/detail?id=79924 Надеюсь, он будет исправлен, но теперь нет обходного пути. Есть предположения? –

+0

@RomanZhukov Спасибо за ссылку на эту проблему, из журнала изменений выяснилось, что эта проблема была исправлена ​​в Android 5.1 (и в выпуске выпущенной версии Webview 40). Я не тестировал старую версию своего приложения, чтобы проверить этот факт, но будет делать так. –

Смежные вопросы