缘由:
项目开发中用,不是所以界面都需要原生开发,也有一部分会用到H5。下面说的问题就是因为项目webView加载H5造成的。
现象:
1、打开一些网页,正常,而有一些就不正常;
2、因为都是同个项目的网页,预测可能这些网页写法不同导致的
3、也可能是手机webkit内核不同造成的
思路:
1、首先如果是手机浏览器内核问题,那么一定是有些手机能打开所以网页 ,有些手机打不开;但结果是所以的测试机展现效果是一致的;
2、根据 1、的结果,得出可能是能打开的网页 和不能打开的网页有不一样的写法;
3、但是对比这些网页,发现并没有异样;
4、那么还是回到代码去解决;
5、debug完整的client
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
titleBuilder.setMiddleTitleText(view.getTitle());
// view.loadUrl("javascript:window.local_obj.showSource('<head>'+"
// + "document.getElementsByTagName('html')[0].innerHTML+'</head>');");
}
@Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return super.shouldInterceptRequest(view, url);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return super.shouldInterceptRequest(view, request);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
});
发现 方法 shouldInterceptRequest 被调用,返回为空,那么这个url是有问题的;
6、用浏览器打开,发现重定向了一个新的url这个url 404
结论:
如果遇到请求网址重定向到一个错误的、不存在的url,就会导致shouldOverrideUrlLoading无法回调,webView无法打开url。
发现很多网友说 webView的 shouldOverrideUrlLoading不调用,现在可以再加上这种情况,重定向的URL网址不存在以至于请求中断,无法回调shouldOverrideUrlLoading方法。
辅助:
1、调试过程中 并没有发现是重定向。于是给大家提供一种重定向的确定方法
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.ViewConfiguration;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.netease.nim.uikit.common.activity.TActivity;
import com.umeng.analytics.MobclickAgent;
import com.yzx.youneed.R;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultRedirectHandler;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
/**
* 通用网页界面
*
* @author lif
*/
public class CommWebViewActivity extends TActivity {
public static final String TAG = CommWebViewActivity.class.getSimpleName();
// 通用网页活动实例
private CommWebViewActivity instance;
protected WebView webView = null;
// 关于我们主页
private String url = "http://www.51ttjd.com";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.common_webview);
findView();
setView();
}
private void findView() {
webView = (WebView) findViewById(R.id.comm_webview);
}
@SuppressLint("SetJavaScriptEnabled")
private void setView() {
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);//设置js可以直接打开窗口,如window.open(),默认为false
webView.getSettings().setJavaScriptEnabled(true);//是否允许执行js,默认为false。设置true时,会提醒可能造成XSS漏洞
webView.getSettings().setSupportZoom(true);//是否可以缩放,默认true
webView.getSettings().setBuiltInZoomControls(true);//是否显示缩放按钮,默认false
webView.getSettings().setUseWideViewPort(true);//设置此属性,可任意比例缩放。大视图模式
webView.getSettings().setLoadWithOverviewMode(true);//和setUseWideViewPort(true)一起解决网页自适应问题
webView.getSettings().setAppCacheEnabled(true);//是否使用缓存
webView.getSettings().setDomStorageEnabled(true);//DOM Storage
// displayWebview.getSettings().setUserAgentString("User-Agent:Android");//设置用户代理,一般不用
// webView.setVerticalScrollbarOverlay(true);
// webView.getSettings().setJavaScriptEnabled(true);
// webView.getSettings().setAllowFileAccess(true);
// webView.getSettings().setDomStorageEnabled(true);
// // webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
// webView.getSettings().setSavePassword(false);// 默认是保存密码,设为false就不会报错.
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return super.shouldOverrideUrlLoading(view, request);
}
// 这个方法在用户试图点开页面上的某个链接时被调用
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url != null) { // 如果想继续加载目标页面则调用下面的语句 //
/*if (url.contains(".apk")) {
Uri uri = Uri.parse(url);
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
} else {
view.loadUrl(url); //
}*/
view.loadUrl(url); //
}
// 如果不想那url就是目标网址,如果想获取目标网页的内容那你可以用HTTP的API把网页扒下来。
// 返回true表示停留在本WebView(不跳转到系统的浏览器)
// return super.shouldOverrideUrlLoading(view, url);
return true;
}
});
// webView.loadUrl(url);
new MyTask().execute(url);
}
private void webViewDestroy() {
if (webView != null) {
webView.getSettings().setBuiltInZoomControls(true);
webView.setVisibility(View.VISIBLE);
long timeout = ViewConfiguration.getZoomControlsTimeout();
// new Timer().schedule(new TimerTask() {
//
// @Override
// public void run() {
// webView.destroy();
// }
// }, timeout);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// webView.clearHistory();
// webView.clearCache(true);
// webView.loadUrl("about:blank");
// webView.freeMemory(); //new code
// webView.pauseTimers(); //new code
// webView.clearView();
webView.destroy();
webView = null;
}
}, timeout);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
webViewDestroy();
}
@Override
protected void onResume() {
super.onResume();
MobclickAgent.onResume(instance);
}
@Override
protected void onPause() {
super.onPause();
MobclickAgent.onPause(instance);
}
private String redirectUrl = null;
public int getPost(String string) {
// TODO Auto-generated method stub
int code = 0;
HttpGet getMethod = new HttpGet(string);
DefaultHttpClient loginClient = new DefaultHttpClient();
MyRedirectHandler redirectHandler = new MyRedirectHandler();
loginClient.setRedirectHandler(redirectHandler);
try {
HttpResponse response = loginClient.execute(getMethod);
code = response.getStatusLine().getStatusCode();
for(Header header:response.getAllHeaders()){
if("Location".equals(header.getName())){
redirectUrl= header.getValue();
break;
}
}
Log.i(TAG, "resCode = " + response.getStatusLine().getStatusCode()); //获取响应码
Log.i(TAG, "result = " + EntityUtils.toString(response.getEntity(), "utf-8"));//获取服务器响应内容
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return code;
}
public class MyTask extends AsyncTask<String, String, Integer> {
@Override
protected Integer doInBackground(String... params) {
// TODO Auto-generated method stub
String url = params[0];
return getPost(url);
}
@Override
protected void onPostExecute(Integer result) {
// TODO Auto-generated method stub
if(result==302&&redirectUrl!=null){//302为临时移动
webView.loadUrl(redirectUrl);
}
}
}
public class MyRedirectHandler extends DefaultRedirectHandler {
@Override
public boolean isRedirectRequested(HttpResponse response,
HttpContext context) {
// TODO Auto-generated method stub
return false;
}
}
}
错误code:
3xx(已重定向) 要完成请求,您需要进一步进行操作。通常,这些状态代码是永远重定向的。Google 建议您在每次请求时使用的重定向要少于 5 个。您可以使用网站管理员工具来查看 Googlebot 在抓取您已重定向的网页时是否会遇到问题。诊断下的抓取错误页中列出了 Googlebot 由于重定向错误而无法抓取的网址。
代码 说明
300(多种选择) 服务器根据请求可执行多种操作。服务器可根据请求者 (User agent) 来选择一项操作,或提供操作列表供请求者选择。
301(永久移动) 请求的网页已被永久移动到新位置。服务器返回此响应(作为对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。您应使用此代码通知 Googlebot 某个网页或网站已被永久移动到新位置。
302(临时移动) 服务器目前正从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置。但由于 Googlebot 会继续抓取原有位置并将其编入索引,因此您不应使用此代码来通知 Googlebot 某个页面或网站已被移动。
303(查看其他位置) 当请求者应对不同的位置进行单独的 GET 请求以检索响应时,服务器会返回此代码。对于除 HEAD 请求之外的所有请求,服务器会自动转到其他位置。
304(未修改)
自从上次请求后,请求的网页未被修改过。服务器返回此响应时,不会返回网页内容。
如果网页自请求者上次请求后再也没有更改过,您应当将服务器配置为返回此响应(称为 If-Modified-Since HTTP 标头)。由于服务器可以告诉 Googlebot 自从上次抓取后网页没有更改过,因此可节省带宽和开销
。
305(使用代理) 请求者只能使用代理访问请求的网页。如果服务器返回此响应,那么,服务器还会指明请求者应当使用的代理。
307(临时重定向) 服务器目前正从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置。但由于 Googlebot 会继续抓取原有位置并将其编入索引,因此您不应使用此代码来通知 Googlebot 某个页面或网站已被移动。