2011-02-09 14 views
5

Tengo un servicio web con el que intento autenticar en segundo plano mediante una vista web. Cuando inicialmente envío la solicitud, funcionará de manera adecuada (fracaso/éxito según las credenciales), pero después parece que recibo una respuesta en caché.Deshabilitar el almacenamiento en caché, las cookies y todo lo demás en un WebView

Aquí está mi vista web código de configuración:

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 se puede ver que tengo dos clases adicionales que controlan mi web View:

  1. Un objeto que proporciona una interfaz para javascript (AddAccountJSInterface)
  2. A WebViewClient

Además, tengo un WebChromeClient, pero solo está disponible para la depuración y estoy bastante seguro de que no interferirá con nada.

La interfaz JS simplemente proporciona una manera fácil de obtener el cuerpo HTML para realizar análisis, por lo que estoy seguro de que ese no es el problema tampoco.

El WebViewClient tiene el siguiente código que hace la mayor parte del trabajo "personalizado" para el enrutamiento basado en varias respuestas del servicio web.

@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 haciendo clic en un botón para enviarlo. La actividad luego toma los datos de 3 campos de texto (shopAddressField, usernameField, passwordField) y luego ejecuta un javascript que rellena algunos datos del formulario (que se cargó en el invisible webView) y luego hace clic en el botón de enviar.

Es la última parte que está estropeando, que parece estar almacenando en caché la respuesta del servidor (¿quizás usando cookies?) Y la devuelve en lugar de preguntar al servidor si los datos son correctos o no.

Un poco de aclaración:

JSInterface es simplemente un objeto de Java que me permite ejecutar código JavaScript en mi vista web 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 código JavaScript que se ejecuta en la vista web:

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 realmente ejecutan jsInterface.setInnerHtml ("") I' Estoy escribiendo demasiado el código HTML que extrajo (para asegurarse de que no estoy obteniendo mis datos anteriores de allí por algún motivo). No

// 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); 
+3

quejarse en Twitter que su pregunta no está recibiendo la atención después de solo 45 minutos es insultante. Si desea respuestas garantizadas por debajo de la hora, contrate un consultor. Mientras tanto, considera explicar qué 'jsInterface.setInnerHTML (" ");' y 'submitJS' son, ya que dices que es donde reside tu problema. – CommonsWare

+0

Disculpas. He agregado algunos detalles más sobre qué está haciendo exactamente el javascript y cómo estoy usando mi objeto java jsInterface. Espero que esto ayude a aclarar la pregunta un poco más. – csaunders

+0

Complemento con este: "android.permission.DELETE_CACHE_FILES" en el archivo de manifiesto. –

Respuesta

2

Así resulta que el problema no se basa en el almacenamiento en caché, las cookies y posiblemente:

En cuanto a mis submitJS es una vez más algo de JavaScript que se ejecuta en mi web View de la siguiente manera.

Al ejecutar javascript en su webView lo hace en un hilo separado y puede ser bastante lento.Esto condujo a una condición de carrera que hizo que el código se ejecutara en el orden incorrecto.

He resuelto este problema utilizando un semáforo como Mutex. Esto me permite evitar que mi getter regrese antes de que el Javascript en la webView pueda ejecutarse.

La interfaz creé 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 forma en que uso esto en mi código es el siguiente:

// 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(); 
+0

No calificaré esto como correcto hasta que reciba un poco de retroalimentación. – csaunders

Cuestiones relacionadas