安卓5.0版本 webview 不回调出错方法问题
安卓5.0版本的webview 不回调出错方法,将网络断开后,只能看到底层chromium报错,:
各个接口都已经尝试:
@Override
public void onPageFinished(WebView view, String url) {
Log.d(TAG,"=====onPageFinished url="+url);
//记录当前URL,判断是否在主业面,处理返回键
mLoadUrl = url;
super.onPageFinished(view, url);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d(TAG,"=====onPageStarted url=" + url);
super.onPageStarted(view, url, favicon);
}
@Override
public void onLoadResource(WebView view, String url){
super.onLoadResource(view, url);
Log.d(TAG,"=====onLoadResource url="+ url);
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
super.onReceivedSslError(view, handler, error);
Log.d(TAG,"=====onReceivedSslError error="+ error);
}
@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm){
super.onReceivedHttpAuthRequest(view, handler, host, realm);
Log.d(TAG,"=====onReceivedHttpAuthRequest host="+ host);
}
// 旧版本,会在新版本中也可能被调用,所以加上一个判断,防止重复显示
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Log.d(TAG,"=====11111onReceivedError errorCode="+ errorCode);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
return;
}
super.onReceivedError(view, errorCode, description, failingUrl);
Log.e(TAG," before M version onReceivedError description=" + description
+" errorCode=" + errorCode);
// 在这里显示自定义错误页,只处理没有连接网络的情况
if (errorCode == -2){
showErrorPage();//显示错误页面
}
}
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
Log.d(TAG,"=====22222onReceivedError error="+ error);
super.onReceivedError(view, request, error);
if (null != error) {
CharSequence errDes = error.getDescription();
int errorCode = error.getErrorCode();
Log.e(TAG," after M version onReceivedError errDes=" + errDes
+ " errorCode=" + errorCode);
// 在这里显示自定义错误页,只处理没有连接网络的情况
if (errorCode == -2){
showErrorPage();//显示错误页面
}
}
}
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
Log.d(TAG,"=====3333onReceivedHttpError errorResponse="+ errorResponse);
super.onReceivedHttpError(view, request, errorResponse);
int statusCode = 0;
String reason = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
statusCode = errorResponse.getStatusCode();
reason = errorResponse.getReasonPhrase();
}
Log.e(TAG," onReceivedHttpError statusCode=" + statusCode
+ "reason=" + reason);
//前端处理
}
只会调用加载资源 onLoadResource 接口, you know why?
最后实在没有办法,参考了别人极力不推荐的方法,自己主动去获取HTTP请求状态码:
https://www.jianshu.com/p/5c16e02ed422
在唯一查到的回调方法中增加这段处理:
/**
* 获取请求状态码
*
* @param url
* @return 请求状态码
*/
private int getResponseCode(String url) {
try {
URL getUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) getUrl.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(5000);
connection.setConnectTimeout(5000);
return connection.getResponseCode();
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
@Override
public void onLoadResource(WebView view, String url){
super.onLoadResource(view, url);
Log.d(TAG,"=====onLoadResource url="+ url);
final String getCodeUrl = url;
Log.d(TAG,"=====getCodeUrl getCodeUrl="+ getCodeUrl);
new Thread(new Runnable() {
@Override
public void run() {
int responseCode = getResponseCode(getCodeUrl);
Log.d(TAG,"=====responseCode=" + responseCode);
if (responseCode == 404 || responseCode == 500) {
Message message = mHandler.obtainMessage();
message.what = responseCode;
mHandler.sendMessage(message);
}
}
}).start();
}
当处于断网情况下时,在加载资源中得道的返回码为 -1, 但是其实有的页面有缓存,依然是可以获取到内容的,此时也可以不用提示无网络。。。
最终解决方案: 增加网络监听处理,当没有网络且安卓版本为5.0版本及其以下版本,采取弹toast提示用户检查网络处理:
/** * 此广播接受器提供给android5.0版本使用,解决webview无网络下不回调出错问题 */ public class MyNetworkReceiver extends BroadcastReceiver { private String TAG = "MyNetworkReceiver"; @Override public void onReceive(Context context, Intent intent) { //**判断当前的网络连接状态是否可用*/ ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = connectivityManager.getActiveNetworkInfo(); if ( info != null && info.isAvailable()){ //当前网络状态可用 int netType = info.getType(); if (netType == ConnectivityManager.TYPE_WIFI){ Log.d(TAG, "wifi available"); }else if (netType == ConnectivityManager.TYPE_MOBILE ){ Log.d(TAG, "data network available"); } WebViewActivity.mNoNetwork = false; }else { //当前网络不可用 Log.d(TAG, "no network"); WebViewActivity.mNoNetwork = true; } } }
//记录网络状态是否改变,给安卓5.0版本使用 public static boolean mNoNetwork;
@Override public void onLoadResource(WebView view, String url){ super.onLoadResource(view, url); // TODO: android5.0 版本,且无网络状态时,发出无网络提示 if((Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) && mNoNetwork){ final String getCodeUrl = url; Log.d(TAG,"onLoadResource getCodeUrl="+ getCodeUrl); new Thread(new Runnable() { @Override public void run() { // FIXME 此处是否还有必要请求 int responseCode = getResponseCode(getCodeUrl); Log.d(TAG," onLoadResource responseCode=" + responseCode); Message message = mHandler.obtainMessage(); message.what = Constants.MSG_FOR_NO_NETWORK; message.obj = responseCode; mHandler.sendMessage(message); } }).start(); } }
//消息处理, 用来处理需要在主线程中调用的方法 // (All WebView methods must be called on the same thread) private Handler mHandler = new Handler(){ public void handleMessage(Message msg) { switch (msg.what) { case Constants.MSG_FOR_NO_NETWORK: //如果获取到的状态码为 -1,弹出网络提示 int code = (int)msg.obj; if(code == -1){ ToastUtil.makeText(WebViewActivity.this, "请检查网络"); } break; default: break; } } };