Android WebView拦截且更改Url

最近做项目,遇到一个需求,因为是国际化项目,在新的国家部署机房,在该机房部署的H5域名和原来的不一样,要求客户端拦截H5,并更改Host。

尝试了几种方案如下:

  1. 重写WebView loadUrl()方法,在该方法中更改Url。
@Override
    public void loadUrl(String url) {
        ......
        url = convertUrl(url);
        ......
    
        // 必须调用super,让系统继续加载新的url
        super.loadUrl(url);
    }
复制代码

上面的方案,在测试中发现,H5页面中有跳转二级页面时,没有走。

  1. 重写WebViewClient 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.
     * @deprecated Use {@link #shouldOverrideUrlLoading(WebView, WebResourceRequest)
     *             shouldOverrideUrlLoading(WebView, WebResourceRequest)} instead.
     */
    @Deprecated
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }

    /**
     * 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.
     *
     * <p>Notes:
     * <ul>
     * <li>This method is not called for requests using the POST "method".</li>
     * <li>This method is also called for subframes with non-http schemes, thus it is
     * strongly disadvised to unconditionally call {@link WebView#loadUrl(String)}
     * with the request's url from inside the method and then return true,
     * as this will make WebView to attempt loading a non-http url, and thus fail.</li>
     * </ul>
     * </p>
     *
     * @param view The WebView that is initiating the callback.
     * @param request Object containing the details of the request.
     * @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, WebResourceRequest request) {
        return shouldOverrideUrlLoading(view, request.getUrl().toString());
    }
复制代码

如果开发没有设置WebViewClient,WebView会让Activity Manager选择合适的处理方法(可能使用浏览器)。如果设置了WebViewClient,该方法返回true,则主程序处理改url,如果返回false,则当前WebView处理,即系统默认处理。(不会执行WebView的loadUrl方法)

最开始的想法是在shouldOverrideUrlLoading()方法更改url,不过发现,这里可以拦截到,但更改后的url,无法让系统默认加载。只能主程序显示调用加载。

@Override
    public boolean shouldOverrideUrlLoading(final String url) {
        if (isInterceptUrlLoading(url)) {
            // 重点处理二级页面跳转的情况
            // 如果直接返回false,会由系统默认加载,则无法改变url,且也不会走到loadUrl中,无法在该方法中更改url
            getWebView().loadUrl(url);
            return true;
        }
        return false;
    }
复制代码
  1. 寻找其他更优解法

上面方法2的解法,会改变原来url的加载方式,所以找了找有没有其他更好的办法。

重写WebViewClient的shouldInterceptRequest方法。

/**
     * Notify the host application of a resource request and allow the
     * application to return the data.  If the return value is null, the WebView
     * will continue to load the resource as usual.  Otherwise, the return
     * response and data will be used.  NOTE: This method is called on a thread
     * other than the UI thread so clients should exercise caution
     * when accessing private data or the view system.
     *
     * @param view The {@link android.webkit.WebView} that is requesting the
     *             resource.
     * @param url The raw url of the resource.
     * @return A {@link android.webkit.WebResourceResponse} containing the
     *         response information or null if the WebView should load the
     *         resource itself.
     * @deprecated Use {@link #shouldInterceptRequest(WebView, WebResourceRequest)
     *             shouldInterceptRequest(WebView, WebResourceRequest)} instead.
     */
    @Deprecated
    public WebResourceResponse shouldInterceptRequest(WebView view,
            String url) {
        return null;
    }

    /**
     * Notify the host application of a resource request and allow the
     * application to return the data.  If the return value is null, the WebView
     * will continue to load the resource as usual.  Otherwise, the return
     * response and data will be used.  NOTE: This method is called on a thread
     * other than the UI thread so clients should exercise caution
     * when accessing private data or the view system.
     *
     * @param view The {@link android.webkit.WebView} that is requesting the
     *             resource.
     * @param request Object containing the details of the request.
     * @return A {@link android.webkit.WebResourceResponse} containing the
     *         response information or null if the WebView should load the
     *         resource itself.
     */
    public WebResourceResponse shouldInterceptRequest(WebView view,
            WebResourceRequest request) {
        return shouldInterceptRequest(view, request.getUrl().toString());
    }
复制代码

该方法可以拦截所有请求,除了Html的页面,其他资源js、css都会拦截到。

通过注释,如果返回null,则WebView还是会默认加载原来的url,需要自己创建WebResourceResponse。

可以在此处做离线资源的加载,但不适合只更改url,因为无法创建WebResourceResponse。

  1. 结论

最后使用方法1和方法2的结合来处理的。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章