安卓5.0版本 webview 不回调出错方法问题

2022-07-31 10:26:40

安卓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;
        }
    }
};
  • 作者:杨武博
  • 原文链接:https://blog.csdn.net/yangwubolwg/article/details/83780708
    更新时间:2022-07-31 10:26:40