Quiero obtener un valor de retorno de Javascript en Android. Puedo hacerlo con iPhone, pero no puedo con Android. Usé loadUrl, pero volvió vacío en lugar de un objeto. Alguien puede ayudarme? Gracias.¿Cómo obtener el valor de retorno de javascript en la vista web de Android?
Respuesta
Use addJavascriptInterface()
para agregar un objeto de Java al entorno de Javascript. Haga que su Javascript invoque un método en ese objeto Java para proporcionar su "valor de retorno".
Aquí es un truco de cómo se puede lograr que:
Añadir este cliente para su WebView:
final class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
}
Ahora en su llamada Javascript a hacer:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
Ahora en el onJsAlert llamada "mensaje" contendrá el valor devuelto.
Este es un truco extremadamente valioso; especialmente cuando estás construyendo una aplicación donde no tienes control sobre el javascript y tienes que conformarte con las funciones existentes. Tenga en cuenta que puede obtener el mismo resultado sin interceptar las alertas JS usando 'boolean public onConsoleMessage (ConsoleMessage consoleMessage)' en lugar de 'onJsAlert' y luego en la llamada javascript' 'webView.loadUrl (" javascript: console.log (functionThatReturnsSomething) ");' - de esa manera dejas las alertas JS en paz. –
La solución con 'WebChromeClient.onConsoleMessage' parece ser más limpia, pero tenga en cuenta que no funciona con algunos dispositivos HTC. Consulte [esta pregunta] (http://stackoverflow.com/questions/4860021/android-problem-with-debugging-javascript-in-webview) para obtener más información. – Piotr
¿Alguna razón para usar addJavascriptInterface no sería preferible? – Keith
Esto es lo que se me ocurrió hoy. Es seguro para subprocesos, razonablemente eficiente y permite la ejecución síncrona de JavaScript desde Java para Android WebView.
Funciona en Android 2.2 en adelante. (Requiere commons-lang porque necesito que mis fragmentos de código pasen a eval() como una cadena de Javascript. Puede eliminar esta dependencia envolviendo el código no entre comillas, sino en function(){}
)
Primero, agregue esto a su Javascript archivo:
function evalJsForAndroid(evalJs_index, jsString) {
var evalJs_result = "";
try {
evalJs_result = ""+eval(jsString);
} catch (e) {
console.log(e);
}
androidInterface.processReturnValue(evalJs_index, evalJs_result);
}
a continuación, añadir esto a su actividad Android:
private Handler handler = new Handler();
private final AtomicInteger evalJsIndex = new AtomicInteger(0);
private final Map<Integer, String> jsReturnValues = new HashMap<Integer, String>();
private final Object jsReturnValueLock = new Object();
private WebView webView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webView = (WebView) findViewById(R.id.webView);
webView.addJavascriptInterface(new MyJavascriptInterface(this), "androidInterface");
}
public String evalJs(final String js) {
final int index = evalJsIndex.incrementAndGet();
handler.post(new Runnable() {
public void run() {
webView.loadUrl("javascript:evalJsForAndroid(" + index + ", " +
"\"" + StringEscapeUtils.escapeEcmaScript(js) + "\")");
}
});
return waitForJsReturnValue(index, 10000);
}
private String waitForJsReturnValue(int index, int waitMs) {
long start = System.currentTimeMillis();
while (true) {
long elapsed = System.currentTimeMillis() - start;
if (elapsed > waitMs)
break;
synchronized (jsReturnValueLock) {
String value = jsReturnValues.remove(index);
if (value != null)
return value;
long toWait = waitMs - (System.currentTimeMillis() - start);
if (toWait > 0)
try {
jsReturnValueLock.wait(toWait);
} catch (InterruptedException e) {
break;
}
else
break;
}
}
Log.e("MyActivity", "Giving up; waited " + (waitMs/1000) + "sec for return value " + index);
return "";
}
private void processJsReturnValue(int index, String value) {
synchronized (jsReturnValueLock) {
jsReturnValues.put(index, value);
jsReturnValueLock.notifyAll();
}
}
private static class MyJavascriptInterface {
private MyActivity activity;
public MyJavascriptInterface(MyActivity activity) {
this.activity = activity;
}
// this annotation is required in Jelly Bean and later:
@JavascriptInterface
public void processReturnValue(int index, String value) {
activity.processJsReturnValue(index, value);
}
}
Gracias por el código anterior: lo adopté en mi proyecto de Android. Sin embargo, hay una trampa en ella, como resultado del mal diseño de la API de Java. La línea: jsReturnValueLock.wait (waitMs - (System.currentTimeMillis() - start)); El valor del argumento de la función wait() a veces puede pasar a evaluar a 0. Y esto significa "esperar infinitamente" - Recibía ocasionalmente errores de "no respuesta". Lo resolví probando: if (transcurrido> = waitMS) break; y no llama de nuevo System.currentTimeMillis() a continuación, pero utilizando el valor transcurrido. Lo mejor sería editar y corregir el código anterior. – gregko
¡Muchas gracias! Estaba viendo eso también y nunca imaginé de dónde venía. – Keith
Pero si ejecuto evalJS en button.click listener, etc ,. waitForJsReturnValue puede hacer que evalJs() cuelgue. Así que webView.loadUrl() dentro de handler.post() puede no tener posibilidad de ejecución porque no se devolvió el oyente button.click. – victorwoo
Igual que Keith
pero la respuesta más corta
webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");
y poner en práctica la función
@JavascriptInterface
public void onData(String value) {
//.. do something with the data
}
No se olvide de quitar el onData
de proguard
lista (Proguard si ha habilitado)
¿Puede explicar la parte 'proguard'? – eugene
@eugene si no sabes de qué se trata, probablemente no lo uses. De todos modos, es algo para habilitar lo que hace que la ingeniería inversa sea más difícil para tu aplicación –
Gracias. Sé que tengo proguard-project.txt en la raíz del proyecto, pero no más que eso. Te pregunto porque tu solución funciona pero obtengo SIGSEGV. Estoy evaluando 'document.getElementById (" my-div "). ScrollTop' para obtener la posición de desplazamiento de' SwipeRefreshLayout :: canChildScrollUp() '. Sospecho que podría ser debido a que la llamada se llama demasiadas veces en un período corto. o 'proguard' que sospecho porque simplemente no sé lo que es .. – eugene
La solución que @Felix Khazin sugirió obras, pero hay una punto clave que falta.
La llamada javascript debe realizarse después de que se cargue la página web en el WebView
. Agregue WebViewClient
al WebView
, junto con el WebChromeClient
.
Ejemplo completo:
El API 19+, la mejor manera de hacer esto es llamar evaluateJavascript en su WebView:
webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() {
@Override public void onReceiveValue(String value) {
// value is the result returned by the Javascript as JSON
}
});
respuesta Relacionado con más detalle: https://stackoverflow.com/a/20377857
- 1. valor de retorno javascript UIWebView
- 2. Obteniendo el valor de retorno del código Javascript en Selenium
- 3. Obtener el valor de retorno de fputcsv
- 4. Obtener el valor de retorno de JOptionPane
- 5. usando javascript en la vista web de Android
- 6. ¿Cómo inspeccionar el valor de retorno de la función de JavaScript en el depurador de Chrome?
- 7. Web SQL SELECCIONE el valor de retorno de la transacción
- 8. ¿Cómo obtener el valor de retorno de xcodebuild?
- 9. ¿Cómo obtener el valor de retorno de CHILD PROCESS?
- 10. Obtener valor de retorno de proceso
- 11. Obtener valor de retorno después de SetTimeout
- 12. Utilizando el valor de retorno de un bloque en JavaScript
- 13. valor de retorno de la función anidada en Javascript
- 14. Cómo establecer el borde para la vista web de Android
- 15. Obtener el valor de retorno de JDBC MSSQL
- 16. Android: el uso de html5 para determinar la geolocalización en la vista web con javascript api
- 17. Obtener el valor de Textbox en Javascript
- 18. Obtener el valor de retorno del procedimiento almacenado en ADO.NET
- 19. cómo optimizar renderspeed en la vista web de Android
- 20. Comprensión de la vista web de Android addjavascriptinterface
- 21. guardar/restaurar el estado de la vista web de android
- 22. JavaScript - Retorno de la función anónima (varScope)
- 23. ¿Cómo obtener la vista de un elemento en la vista de lista en Android?
- 24. Obtener valor de retorno de procedimiento almacenado en C#
- 25. Cómo obtener el ancho y alto de una vista web en android
- 26. Obtener el valor de retorno de una función en la configuración de Inno
- 27. Problema raro en la vista web de Android con lienzo
- 28. ¿Cómo obtener el valor de retorno de matlab en el script bash?
- 29. "sys.getrefcount()" valor de retorno
- 30. ¿La alerta no aparece desde la vista web en android?
¿Cómo puedo hacer eso en una situación como http: // stackoverflow.com/questions/5521191/returning-a-value-from-javascript-function-in-android – vnshetty
Esto no ayuda si su js no escribe en este objeto y no puede tocar el js. –
@PacMani: Use 'loadUrl (" javascript: ... ")' (Nivel de API 1-18) o 'evalúeJavascript()' (Nivel de API 19+) para evaluar su propio JavaScript en el contexto de la Web actualmente cargada página. – CommonsWare