我一直在 Android 和 iOS 上开发网络应用程序并使用 WebView 。在 iPhone 上一切正常,但在 Android 上却不能在所有设备上正常工作,这让我抓狂。在五台 Android 设备上它运行良好,但在两台设备上它不会比登录页面更进一步。但是,它确实适用于浏览器中的移动网站(而非应用程序)。
移动应用程序无法运行的设备是 HTC One (v4.3) 和 Acer Liquid Z3 (v4.2)。另一台设备也是 HTC One (v4.3) 它确实可以工作,这使得问题很难理解和解决。
应用程序打开时的第一个窗口是一个简单的登录窗口。在它不工作的设备上,它只是重新加载页面,用户可以再次登录。登录信息与数据库中的详细信息进行核对。当它正常工作(或在浏览器中打开)时,它会加载到一个新页面。
主要 Activity .java:
public class MainActivity extends Activity {
WebView mWebView;
private ProgressBar loadingProgressBar;
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new DivumWebViewClient());
mWebView.loadUrl("http://www.xxxx.com/index.php");
loadingProgressBar = (ProgressBar) findViewById(R.id.progressbar_title);
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
loadingProgressBar.setProgress(newProgress);
if (newProgress == 100) {
loadingProgressBar.setVisibility(View.GONE);
} else {
loadingProgressBar.setVisibility(View.VISIBLE);
}
}
});
}
private class DivumWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
}
索引.php
.....
<body class="blue-bg">
<?php
if (isset($_GET['error'])) {
echo '<p class="error">Error Logging In!</p>';
}
sec_session_start();
if (isset($_POST['email'], $_POST['p'])) {
$email = $_POST['email'];
$password = $_POST['p'];
if (login($email, $password, $mysqli) == true) {
// Login success
header('Location: dashboard.php');
exit;
} else if(login($email, $password, $mysqli) == false){
$error['error'] = "<p>Enter login details:</p>\n";
}
}
?>
<div class="signin" style="margin-top: 0;">
<div class="signin-body">
<a href="index.php" title="Login" class="pull-right">
<img src="../assets/images/logo.jpg" title="Login" alt="Login">
</a>
<br><h3>Login</h3>
<?=$error['error']?>
<form action="<?=$_SERVER['PHP_SELF']?>" id="login-validatie" method="post" name="login_form">
<div class="form-group">
<input type="text" class="form-control" placeholder="Emailadres" name="email" id="email">
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="Wachtwoord" name="password" id="password">
</div>
<div class="form-group clearfix">
<input type="submit" onclick="formhash(this.form, this.form.password);" class="btn btn-med blue-bg pull-right" value="Inloggen">
</div>
<hr>
</form>
</div>
</div>
<script src="../assets/js/scripts.js"></script>
</body>
</html>
不知道是bug还是什么。奇怪的是它适用于大多数设备,但不适用于某些设备。它也适用于浏览器,这让我觉得它与 Android 中的 WebView 有关。我处于死胡同,感谢每一个帮助。谢谢!
更新 我终于找到了问题所在,它与表单散列有关。密码在 web View 中的某些 Android 设备上给出了不同的 sha512 哈希值,这使得无法登录。不知道是不是Android的web view在某些设备上的限制,有谁知道如何解决这个问题?
表单.js
function formhash(form, password) {
// Create a new element input, this will be our hashed password field.
var p = document.createElement("input");
// Add the new element to our form.
p.name = "p";
p.type = "hidden";
p.value = hex_sha512(password.value);
form.appendChild(p);
// Make sure the plaintext password doesn't get sent.
password.value = "";
// Finally submit the form.
form.submit();
}
函数.php
function login($email, $password, $mysqli) {
// Using prepared statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, password, salt FROM x WHERE email = ? LIMIT 1")) {
$stmt->bind_param('s', $email); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($user_id, $username, $db_password, $salt);
$stmt->fetch();
// hash the password with the unique salt.
$password = hash('sha512', $password . $salt);
?><script> var x; x = "<?php print($password); ?>"; console.log("Logging: password is " + x); </script><?
if ($stmt->num_rows == 1) {
// If the user exists we check if the account is locked
// from too many login attempts
if (checkbrute($user_id, $mysqli) == true) {
// Account is locked
// Send an email to user saying their account is locked
return false;
} else {
// Check if the password in the database matches
// the password the user submitted.
if ($db_password == $password) {
// Password is correct!
// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];
// XSS protection as we might print this value
$user_id = preg_replace("/[^0-9]+/", "", $user_id);
$_SESSION['user_id'] = $user_id;
// XSS protection as we might print this value
$username = preg_replace("/[^a-zA-Z0-9_\-]+/",
"",
$username);
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512',
$password . $user_browser);
// Login successful.
return true;
} else {
// Password is not correct
// We record this attempt in the database
$now = time();
$mysqli->query("INSERT INTO login_attempts(user_id, time)
VALUES ('$user_id', '$now')");
return false;
}
}
} else {
// No user exists.
return false;
}
}
}
在 iPhone 应用程序、Android 浏览器、桌面浏览器或某些 Android 应用程序上使用时,它会提供一个 sha5 哈希值:c7d9a2def4f8d0f9c4b65d7522566ed33549b266174b2b12ae7f7b047e7efed2e92d18e552d1c812f073e794d16feb8ccf9df85399c475f24571472dece2d9b2
但在某些 Android 设备上,由于某些奇怪的原因使用相同的密码时,它会给出两个哈希值之一:
98488504186f9f69041c80217c311cfb4772f46319c945d3bc30c0c2db5650e675774bc6978749770b598e70d4553ec0391e7d3ec0b56d51eef51eeadbb7e10e
a3e08c365ef82d4256d8e58fd63b53d63d50b6b3cac3cdaba395cc73289e5f955491f11f06408c2c6e6ae531d69ddb10f234ecef0cf375d9782abea27909c9ef
最佳答案
我之前也遇到过这个问题,我的 webview 无法在当前窗口中打开一个 url,不久之后 android os 会获取该 url 并尝试在浏览器中打开它。我有一个非常相似的实现。
我相信这直接来自 documentation 是您要寻找的:
创建和设置 WebViewClient 子类。当发生影响内容呈现的事情时将调用它,例如错误或表单提交。您还可以在此处拦截 URL 加载(通过 shouldOverrideUrlLoading())。
shouldOverrideUrlLoading()
方法告诉 webview 我想处理通过此 WebView 提交的所有 url 的加载操作
您可以在 My Github Project 从第 226 行开始看到我是如何处理这个问题的,我在其中添加了一个额外的内部类,它扩展了 WebViewClient 类。
边注
这适用于我支持的大多数设备上的应用程序。但您可能还想确保您的 URL 是完全合格的。我发现当我使用的任何网址都没有
http://
在它的前面,WebView 将无法加载 URL,即使使用 Additional WebViewClient。对象和 shouldOverrideUrlLoading() 调用。
您是否在加载失败后尝试过以下操作?看看这是否会刷新 webview 的状态,一旦刷新,就向您真正想要的 URL 发出新请求。
WebView.loadUrl("about:blank")
您试过在 WebView 中不使用 javascript 吗?
我听说这可能是一个潜在的安全漏洞,并且它对呈现网页的 WebView 有相当大的影响。
祝你好运!
更新
看起来您的问题不在于您的 webview,而是您的 php 脚本是否正确?
尝试在 Java 中使用这个创建密码时,或者检查用户密码是否正确:
String password = "123456";
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes());
byte byteData[] = md.digest();
您实际上只需要在应用程序或服务器脚本的一侧执行此操作。我会从应用程序端选择,因为这样您可以通过网络而不是纯文本发送散列密码。
关于javascript - Android Webview,formhash 在某些 Android 设备上不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21888374/