Отключение кеширования, куки и всего остального в WebView - PullRequest
5 голосов
/ 09 февраля 2011

У меня есть веб-сервис, с которым я пытаюсь пройти аутентификацию в фоновом режиме, используя веб-просмотр.Когда я первоначально отправляю запрос, он будет работать надлежащим образом (сбой / успех на основе учетных данных), но после того, как мне кажется, я получаю кэшированный ответ.

Вот мой код установки веб-просмотра:

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));

Итак, как вы можете видеть, у меня есть два дополнительных класса, управляющих моим webView:

  1. Объект, который обеспечивает интерфейс для javascript (AddAccountJSInterface)
  2. A WebViewClient

Кроме того, у меня есть WebChromeClient, но он есть только для отладки, и я уверен, что он никому не помешает.

Интерфейс JS просто обеспечивает простой способ получения телаHTML для выполнения анализа, поэтому я уверен, что это тоже не проблема.

В WebViewClient содержится следующий код, который выполняет большую часть «настраиваемой» работы по маршрутизации на основе различных ответов веб-службы..

    @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);
            }
        }
    }

В моей деятельности у меня есть 3 текстовых поля, которые мне нужно заполнить, а затем нажать кнопку, чтобы отправить его.Затем действие получает данные из 3 текстовых полей (shopAddressField, usernameField, passwordField), а затем выполняет некоторый javascript, который заполняет некоторые данные формы (который был загружен в невидимое веб-представление), затем нажимает кнопку отправки.

Этопоследняя часть, которая не работает, которая, кажется, кэширует ответ от сервера (возможно, с использованием файлов cookie?) и возвращает его вместо того, чтобы спрашивать сервер, верны ли данные.

Немногоразъяснение:

JSInterface - это просто объект Java, который позволяет мне выполнять JavaScript в моем веб-представлении, которое связано с функцией в этом объекте.В моем случае мой JSInterface имеет одну функцию, которая является setInnerHtml (String html).

Это javascript, который выполняется в веб-просмотре:

javascript:window.ADDACOUNTJSINTERFACE.setInnerHTML(document.body.innerHTML)

И это функция setInnerHtml:

public void setInnerHtml(String innerHtml) {
    this.innerHtml = innerHtml;
}

Поэтому, когда я на самом деле выполняю jsInterface.setInnerHtml (""), я просто перезаписываю извлеченный HTML-код (чтобы по какой-то причине не получить оттуда свои старые данные)).

Что касается моего submitJS, то это снова некоторый Javascript, который выполняется в моем webView следующим образом:

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

1 Ответ

3 голосов
/ 10 февраля 2011

Получается, что проблема не в кешировании, а, возможно, не в файлах cookie.

При выполнении javascript в вашем webView он делает это в отдельном потоке и может быть довольно медленным. Это привело к состоянию гонки, из-за которого код выполнялся в неправильном порядке.

Я решил эту проблему, используя семафор в качестве мьютекса. Это позволяет мне предотвратить возврат моего метода получения до того, как Javascript в webView сможет выполнить.

Интерфейс, который я создал сейчас, выглядит следующим образом:

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;
    }
}

Теперь я использую это в своем коде следующим образом:

// 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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...