Deshabilitar el almacenamiento en caché, las cookies y todo lo demás en un WebView
Tengo un webservice que estoy intentando authenticar con en el fondo usando un webview. Cuando inicialmente enviar la solicitud que funcionará adecuadamente (fracaso / éxito basado en credenciales), pero después de que parece que estoy recibiendo una respuesta en caché.
Aquí está mi código de configuración de la webview:
- Phonegap - manejo de la notificación push una vez que he dejado el ámbito del índice con window.location.replace
- Abrir desplegable desde javascript
- Redirigir a appstore o google play
- Método multiplataforma para eliminar la barra de direcciones de una aplicación web para móviles
- Cómo implementar Google Tag Manager en Córdoba
WebView browser = new WebView(this); WebSettings settings = browser.getSettings(); settings.setJavaScriptEnabled(true); settings.setSavePassword(false); settings.setCacheMode(WebSettings.LOAD_NO_CACHE); settings.setAppCacheEnabled(false); browser.setWebChromeClient(new WebChromeClient() { public void onProgressChanged(WebView view, int progress) { Log.d("BROWSERPROGRESS", Integer.toString(progress)); } }); jsInterface = new AddAccountJSInterface(); browser.addJavascriptInterface(jsInterface, "ADDACCOUNTJSINTERFACE"); browser.setWebViewClient(new AddAccountClient(this));
Así como usted puede ver que tengo dos clases adicionales que controlan mi webView:
- Un objeto que proporciona una interfaz para javascript (AddAccountJSInterface)
- Un WebViewClient
Además tengo un WebChromeClient, pero sólo está allí para la depuración y estoy bastante seguro de que no interferirá con nada.
La interfaz JS simplemente proporciona una forma sencilla de obtener el HTML del cuerpo para realizar análisis, por lo que estoy seguro de que tampoco es el problema.
El WebViewClient tiene el código siguiente en él que hace la mayor parte del trabajo "de encargo" para el enrutamiento basado en varias respuestas del webservice.
@Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if(url.contains(INSTALL_PREFIX)) { HashMap<String, String> params = extractParameters(url); verificationComplete(params); return true; } return false; } @Override public void onPageFinished(WebView view, String url){ if(invalidShop(view)) { Toast.makeText(context, context.getString(R.string.no_find_shop), Toast.LENGTH_SHORT).show(); shopAddressField.requestFocus(); replaceUiElements(loadingBar, addAccountButton); } else if(url.contains(ADMIN_AUTH_LOGIN)) { if(invalidLogin(view)) { Toast.makeText(context, context.getString(R.string.invalid_login),Toast.LENGTH_SHORT).show(); emailField.requestFocus(); replaceUiElements(loadingBar, addAccountButton); } else { String email = emailField.getText().toString(); String password = passwordField.getText().toString(); String submitJS = String.format(FORM_SUBMISSION_JS, email, password); jsInterface.setInnerHTML(""); browser.loadUrl(submitJS); } } }
En mi actividad tengo 3 campos de texto que necesito llenar seguido de hacer clic en un botón para enviarlo. La actividad entonces toma los datos de 3 campos de texto (shopAddressField, usernameField, passwordField) y luego ejecuta algunos javascript que rellena algunos datos de formulario (que fue cargado en el invisible webView) y luego hace clic en el botón Enviar.
Es la última parte que está estropeando, que parece estar almacenando en caché la respuesta del servidor (tal vez usando cookies?) Y devolver que en lugar de preguntar al servidor si los datos son correctos o no.
Un poco de aclaración:
JSInterface es simplemente un objeto Java que me permite ejecutar javascript en mi webview que está vinculado a una función dentro de ese objeto. En mi caso mi JSInterface tiene una función que es setInnerHtml (String html).
Este es el javascript que se ejecuta en la webview:
javascript:window.ADDACOUNTJSINTERFACE.setInnerHTML(document.body.innerHTML)
Y esta es la función setInnerHtml:
public void setInnerHtml(String innerHtml) { this.innerHtml = innerHtml; }
Así que cuando ejecuto jsInterface.setInnerHtml ("") simplemente estoy escribiendo el código HTML que se ha extraído (para estar seguro de que no estoy recibiendo mis datos antiguos de allí por alguna razón).
En cuanto a mi submitJS es de nuevo un poco de Javascript que se ejecuta en mi webView de la siguiente manera:
// submitJS will be something like this once all the credentials have been set // Note: I know that the server will make jQuery available // Note: Much of the Java string formatting has been removed to help clarify // the code. String submitJS = "javascript:(function() { $('login-input').value='username'; $('password').value='password'; $('sign-in-form').up().submit(); })()" // I then simply get the webview to execute the javascript above webView.loadData(submitJS);
- Cómo agregar animaciones personalizadas en Google Map V3 Marker cuando suelto cada marcador uno por uno?
- Error de seguridad con iframe
- Diferencia entre la aplicación web y la respuesta táctil del teléfono
- Implementar la entrada de pago Stripe en la aplicación Cordova / Phonegap
- Deshabilitar las cookies en el navegador de Android no funciona
- Captura de firma en PhoneGap
- ¿Cómo encajar en la pantalla después de cambiar el ancho de la ventana de visualización en el cambio de orientación?
- Jquery 1.6.2 funciona en el emulador de Android 2.1 pero no en el Samsung Galaxy S
Por lo que resulta que el problema no se basa en el almacenamiento en caché, y posiblemente no las cookies.
Al ejecutar javascript en su webView que hace esto en un hilo separado y puede ser bastante lento. Esto condujo a una condición de carrera que provocó que el código se ejecutara en el orden incorrecto.
He resuelto este problema utilizando un semáforo como un Mutex. Esto me permite evitar que mi getter regrese antes de que el Javascript en el webView sea capaz de ejecutar.
La interfaz que he creado ahora se ve así:
private class AddAccountJSInterface { private final String TAG = getClass().getName().toUpperCase(); private Semaphore mutex = new Semaphore(1, false); private String innerHTML; public void aquireSemaphore() { Log.d(TAG, "Attempting to lock semaphore"); try { mutex.acquire(); } catch(InterruptedException e) { Log.d(TAG, "Oh snap, we got interrupted. Just going to abort."); return; } Log.d(TAG, "Semaphore has been aquired"); } @SuppressWarnings("unused") public void setInnerHTML(String html) { this.innerHTML = html; Log.d(TAG, "setInnerHTML is now releasing semaphore."); mutex.release(); Log.d(TAG, "setInnerHTML has successfully released the semaphore."); } public synchronized String getInnerHTML() { Log.d(TAG, "getInnerHTML attempting to aquire semaphore, may block..."); String innerHTML = ""; try { mutex.acquire(); Log.d(TAG, "getInnerHTML has aquired the semaphore, grabbing data."); innerHTML = this.innerHTML; Log.d(TAG, "getInnerHTML no longer needs semaphore, releasing"); mutex.release(); } catch (InterruptedException e) { Log.d(TAG, "Something has gone wrong while attempting to aquire semaphore, aborting"); } return innerHTML; } }
Ahora la manera que uso esto en mi código es como sigue:
// I have access to the jsInterface object which is an instance of the class above as well as a webView which I will be executing the javascript on. String getInnerHtmlJS = "javascript:window.MYJSINTERFACE.setInnerHTML(document.body.innerHTML);" jsInterface.aquireSemaphore() // Execute my JS on the webview jsInterface.loadUrl(getInnerHtmlJS) // Now we get our inner HTML // Note: getInnerHTML will block since it must wait for the setInnerHTML (executed via the JS) function to release the semaphore String theInnerHTML = jsInterface.getInnerHTML();
- Ubicación de Android getBearing () devuelve siempre 0
- Detectar evento de desplazamiento en el navegador de Android