禁止在web视图缓存,cookies和其他一切 [英] Disabling caching, cookies and everything else in a WebView

查看:188
本文介绍了禁止在web视图缓存,cookies和其他一切的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个web服务,我想在后台使用的WebView进行身份验证。当我最初发送请求,将正常进行(基于凭据失败/成功),但似乎我得到一个缓存的响应之后。

下面是我的WebView设置code:

 的WebView浏览器=新的WebView(本);
WebSettings设置= browser.getSettings();
settings.setJavaScriptEnabled(真正的);
settings.setSavePassword(假);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setAppCacheEnabled(假);
browser.setWebChromeClient(新WebChromeClient(){
    公共无效onProgressChanged(web视图来看,INT进度){
    Log.d(BROWSERPROGRESS,Integer.toString(正在进行中));
}
});
jsInterface =新AddAccountJSInterface();
browser.addJavascriptInterface(jsInterfaceADDACCOUNTJSINTERFACE);
browser.setWebViewClient(新AddAccountClient(本));
 

所以你可以看到我有两个其他类控制我的web视图:

  1. ,它为JavaScript的一个接口的对象(AddAccountJSInterface)
  2. 系统WebViewClient

此外我有一个WebChromeClient,但它只有在那里进行调试和我pretty的确保它不会与任何干扰。

JS的接口只提供了让身体的HTML进行分析的一个简单的方法,所以我相信这不是问题无论是。

该WebViewClient具有以下code在这其中做了大部分的基础上从WebService各种反应的自定义工作的路由。

  @覆盖
    公共布尔shouldOverrideUrlLoading(web视图查看,字符串URL){
        如果(url.contains(INSTALL_ preFIX)){
            HashMap的<字符串,字符串> PARAMS = extractParameters(URL);
            verificationComplete(PARAMS);
            返回true;
        }
        返回false;
    }

    @覆盖
    公共无效onPageFinished(web视图查看,字符串URL){
        如果(invalidShop(视图)){
            Toast.makeText(上下文,context.getString(R.string.no_find_shop),Toast.LENGTH_SHORT).show();
            shopAddressField.requestFocus();
            replaceUiElements(loadingBar,addAccountButton);
        }否则,如果(url.contains(ADMIN_AUTH_LOGIN)){
            如果(invalidLogin(视图)){
                Toast.makeText(上下文,context.getString(R.string.invalid_login),Toast.LENGTH_SHORT).show();
                emailField.requestFocus();
                replaceUiElements(loadingBar,addAccountButton);
            } 其他 {
                。字符串email = emailField.getText()的toString();
                字符串password = passwordField.getText()的toString()。
                字符串submitJS =的String.Format(FORM_SUBMISSION_JS,电子邮件,密码);

                jsInterface.setInnerHTML();

                browser.loadUrl(submitJS);
            }
        }
    }
 

在我的活动我有我需要填写依次点击一个按钮提交3文本字段。活动则需要从3文本字段(shopAddressField,usernameField,passwordField)数据,然后执行一些JavaScript用于填充某种形式的数据(这是在看不见的web视图加载),然后点击提交按钮。

有最后一部分被搞乱,这似乎是缓存从服务器(可能使用cookies吗?)的响应和返回,而不是该询问服务器如果数据是正确的或不

澄清一下:

JSInterface是一个简单的Java对象,让我在我的WebView绑定在该对象中的函数执行的JavaScript。在我的情况我JSInterface有一个功能是setInnerHtml(字符串HTML)。

这是对的WebView执行的JavaScript:

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

这是setInnerHtml功能:

 公共无效setInnerHtml(字符串的innerHTML){
    this.innerHtml = innerHTML的;
}
 

所以,当我实际执行jsInterface.setInnerHtml(),我只是在写作这是拉在HTML(以确保我不会让我的旧数据从那里出于某种原因)。

至于我submitJS它再次是对我的web视图执行一些JavaScript如下:

  // submitJS会是这样的,一旦所有的证书都被设置
//注:我知道,服务器将jQuery的可用
//注:大部分的Java字符串格式已被删除,以帮助澄清
//在code。
字符串submitJS =
    的JavaScript:(函数(){
        $('登录输入')值='用户名';
        $('密码')值='密码';
        $('签到形式')上()提交()。
    })()
//我后来干脆拿到的WebView执行上面的JavaScript
webView.loadData(submitJS);
 

解决方案

因此​​,原来不是基于问题周围的缓存,可能不是饼干。

在你的web视图执行的JavaScript它这样做在一个单独的线程,可以是相当缓慢。这导致造成code,以错误的顺序执行的竞争条件。

我用信号量,互斥锁解决了这个问题。这使我prevent我消气,从返回前的使用上的JavaScript web视图能够执行。

我现在创建的接口看起来是这样的:

 私有类AddAccountJSInterface {
    私人最终字符串变量=的getClass()的getName()与toUpperCase()。
    私人信号灯互斥=新的信号量(1,假);
    私人字符串的innerHTML;

    公共无效aquireSemaphore(){
        Log.d(TAG,试图锁定信号量);
        尝试 {
            mutex.acquire();
        }赶上(InterruptedException异常E){
            Log.d(TAG,哦单元,我们被中断刚准备放弃。);
            返回;
        }
        Log.d(TAG,信号灯已经获得性);
    }

    @燮pressWarnings(未使用)
    公共无效setInnerHTML(字符串HTML){
            this.innerHTML = HTML;
            Log.d(TAG,setInnerHTML现在释放信号。);
            mutex.release();
            Log.d(TAG,setInnerHTML已经成功发布了信号。);
    }

    公共同步串getInnerHTML(){
        Log.d(TAG,getInnerHTML试图将收购信号,可能会阻止......);
        字符串的innerHTML =;
        尝试 {
            mutex.acquire();

            Log.d(TAG,getInnerHTML已经获得性的信号,抓住数据。);
            的innerHTML = this.innerHTML;

            Log.d(TAG,getInnerHTML不再需要信号量,释放);
            mutex.release();
        }赶上(InterruptedException异常E){
            Log.d(TAG,有些事情已经在尝试将收购信号,中止错误);
        }

        返回的innerHTML;
    }
}
 

现在我用这个在我的code的方法如下:

  //我有机会获得jsInterface对象也就是上面的类的实例,以及我将要执行的JavaScript的一个web视图。
字符串getInnerHtmlJS =JavaScript的:window.MYJSINTERFACE.setInnerHTML(document.body.innerHTML);
jsInterface.aquireSemaphore()
//执行上的WebView我的JS
jsInterface.loadUrl(getInnerHtmlJS)
//现在我们得到了我们的内心HTML
//注意:getInnerHTML将阻止,因为它必须等待setInnerHTML(通过执行JS)函数来释放信号量
串theInnerHTML = jsInterface.getInnerHTML();
 

I have a webservice that I am trying to authenticate with in the background using a webview. When I initially send the request it will work appropriately (failure/success based on credentials), but after it seems like I am getting a cached response.

Here is my webview setup code:

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

So as you may see I have two additional classes controlling my webView:

  1. An object that provides an interface for javascript (AddAccountJSInterface)
  2. A WebViewClient

Additionally I do have a WebChromeClient, but it's only there for debugging and I'm pretty sure that it won't interfere with anything.

The JS interface simply provides an easy way of getting the body HTML for performing analysis, so I'm confident that isn't the issue either.

The WebViewClient has the following code in it which does most of the "custom" work for routing based on various responses from the 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);
            }
        }
    }

In my activity I have 3 text fields that I need to fill followed by clicking a button to submit it. The activity then takes in the data from 3 text fields (shopAddressField, usernameField, passwordField) and then executes some javascript that populates some form data (which was loaded in the invisible webView) then clicks the submit button.

It is the last part that is messing up, which appears to be caching the response from the server (perhaps using cookies?) and return that instead of asking the server if the data is correct or not.

A bit of clarification:

JSInterface is simply a Java object that allows me to execute javascript on my webview which is tied to a function within that object. In my case my JSInterface has one function which is setInnerHtml(String html).

This is the javascript that is executed on the webview:

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

And this is the setInnerHtml function:

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

So when I actually execute jsInterface.setInnerHtml("") I'm just over-writing the HTML that was pulled in (to be sure I'm not getting my old data from there for some reason).

As for my submitJS it is once again some Javascript that is executed on my webView as follows:

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

解决方案

So it turns out the problem wasn't based around the Caching, and possibly not cookies.

When executing javascript on your webView it does this in a separate thread and can be quite slow. This lead to a race condition which caused code to be executed in the wrong order.

I've solved this problem by using a Semaphore as a Mutex. This allows me to prevent my getter from returning before the Javascript on the webView is able to execute.

The interface I created now looks like this:

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

Now the way I use this in my code is as follows:

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

这篇关于禁止在web视图缓存,cookies和其他一切的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆