Webview资源请求的拦截

Posted by JackPeng on October 24, 2016

Webview资源请求的拦截一般有以下几种实现方法:

一 shouldOverrideUrlLoading和loadUrl

shouldOverrideUrlLoading方法的官方说明如下:

 /**
 * Give the host application a chance to take over the control when a new
 * url is about to be loaded in the current WebView. If WebViewClient is not
 * provided, by default WebView will ask Activity Manager to choose the
 * proper handler for the url. If WebViewClient is provided, return true
 * means the host application handles the url, while return false means the
 * current WebView handles the url.
 * This method is not called for requests using the POST "method".
 *
 * @param view The WebView that is initiating the callback.
 * @param url The url to be loaded.
 * @return True if the host application wants to leave the current WebView
 *         and handle the url itself, otherwise return false.
 */
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    return false;
}

返回值说明

该方法位于WebViewClient中,使用分为以下三种情况:

  • 1 webview未设置WebViewClient,则点击一个链接后,交由系统处理,系统会弹出浏览器列表,让用户选择。

  • 2 webview设置了WebViewClient,而且shouldOverrideUrlLoading返回false(默认),则交由当前webview处理该点击事件。

  • 3 webview设置了WebViewClient,而且shouldOverrideUrlLoading返回true,则交由webview的宿主应用处理。

调用时机

当点击h5页面上一个链接打开新的页面时,webview的loadUrl方法在其后被调用。因此可以知道,要想拦截一个新的页面可以在loadUrl方法中拦截,替换,修改url。

shouldInterceptRequest方法

从 Android API 11 (3.0) 开始,WebView 开始在 WebViewClient 内提供了这样一条 API ,如下:

public WebResourceResponse shouldInterceptRequest(WebView view, String url)  

就是说只要实现 WebViewClient 的 shouldInterceptRequest 方法,然后调用 WebView 的setWebViewClient 就可以了。

但是,在 API21 以上又弃用了上述 API,使用了一条新的 API,如下:

public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) 

使用方法如下:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
        Uri uri = request.getUrl();
        if (uri != null) {
            WebResourceResponse response = getWebResourceResponse(uri.toString());
            if (response != null) return response;
        }

        return super.shouldInterceptRequest(view, request);
    }

    @Nullable
    private WebResourceResponse getWebResourceResponse(String url) {
        try {
            if (url != null && url.contains("kaide.com")) {
                URL newUrl = new URL(appendDeviceInfo(url));
                URLConnection connection = newUrl.openConnection();
                return new WebResourceResponse(connection.getContentType(), connection.getHeaderField("encoding"), connection.getInputStream());
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        WebResourceResponse response = getWebResourceResponse(url);
        if (response != null) return response;
        return super.shouldInterceptRequest(view, url);
    }

该方法可以拦截各种资源的请求,但需要自己处理网络访问,以及获取charset,同时不能进行耗时操作,需要开启异步线程。