csa*_*ers 5 javascript android android-webview
我有一个web服务,我试图在后台使用webview进行身份验证.当我最初发送请求时,它将正常工作(基于凭据的失败/成功),但看起来我似乎得到了缓存响应.
这是我的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));
Run Code Online (Sandbox Code Playgroud)
因此,您可能会看到我有两个额外的类来控制我的webView:
另外我有一个WebChromeClient,但它只用于调试,我很确定它不会干扰任何事情.
JS界面简单地提供了一种简单的方法来获取正文HTML以进行分析,所以我相信这也不是问题.
WebViewClient中包含以下代码,该代码根据来自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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我的活动中,我需要填写3个文本字段,然后单击按钮进行提交.然后,活动从3个文本字段(shopAddressField,usernameField,passwordField)中获取数据,然后执行一些填充某些表单数据的javascript(在不可见的webView中加载),然后单击提交按钮.
这是最后一个搞乱的部分,似乎是缓存来自服务器的响应(可能使用cookie?)并返回而不是询问服务器数据是否正确.
一点澄清:
JSInterface只是一个Java对象,它允许我在我的webview上执行javascript,它与该对象中的一个函数相关联.在我的例子中,我的JSInterface有一个函数是setInnerHtml(String html).
这是在webview上执行的javascript:
javascript:window.ADDACOUNTJSINTERFACE.setInnerHTML(document.body.innerHTML)
Run Code Online (Sandbox Code Playgroud)
这是setInnerHtml函数:
public void setInnerHtml(String innerHtml) {
this.innerHtml = innerHtml;
}
Run Code Online (Sandbox Code Playgroud)
因此,当我实际执行jsInterface.setInnerHtml("")时,我只是覆盖了所引入的HTML(为了确保我没有从那里获取旧数据).
至于我的submitJS,它再次是我在webView上执行的一些Javascript,如下所示:
// 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);
Run Code Online (Sandbox Code Playgroud)
所以事实证明问题不是基于缓存,也可能不是 cookie。
当在 webView 上执行 javascript 时,它会在单独的线程中执行此操作,并且速度可能会很慢。这会导致竞争条件,导致代码以错误的顺序执行。
我通过使用信号量作为互斥体解决了这个问题。这允许我阻止 getter 在 webView 上的 Javascript 能够执行之前返回。
我现在创建的界面如下所示:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我在代码中使用它的方式如下:
// 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();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6607 次 |
| 最近记录: |