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:

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:

  1. Un objeto que proporciona una interfaz para javascript (AddAccountJSInterface)
  2. 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); 

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(); 
  • Phonegap, jQueryMobile y servicio web
  • Android WebView reproducir audio con javascript
  • Detener mi aplicación de dormir (Cordova / Android)
  • JavaScript La geolocalización no funciona en todos los navegadores de Android: funciona en iOS y PC
  • Cambio de hoja de estilo con Javascript basado en navegador
  • Android webview javascript no funciona con loadDataWithBaseUrl
  • ¿Cómo obtener el nombre de la ciudad de la latitud y la longitud en la brecha telefónica?
  • ¿Se puede depurar el javascript en el navegador nativo de una tableta Samsung?
  • UnableToResolveError: no se puede resolver el módulo `merge` desde Bibliotecas / ART / React ART.js nativo
  • Navegador Android: touchcancel está siendo disparado aunque touchmove tiene preventDefault
  • Cordova FileTransfer Error de escritura (Código 1)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.