Webview shouldInterceptRequest示例

38
我需要了解shouldinterceptrequest方法的工作原理。我不知道如何创建和处理此方法以读取和替换CSS链接。谢谢!
2个回答

70

简单来说,它的工作原理与 shouldOverrideUrlLoading(WebView view, String url) 非常相似,就像在 WebView教程 中所示。

为了让您开始使用,请参见下面的代码。您只需覆盖 WebViewClient 的 shouldInterceptRequest(WebView view, String url) 方法即可。显然,您不必内联执行此操作,但出于紧凑性的考虑,我是这样做的:

    WebView webview = (WebView) findViewById(R.id.webview);
    webview.setWebViewClient(new WebViewClient() {
        @Override
        public WebResourceResponse shouldInterceptRequest (final WebView view, String url) {
            if (url.contains(".css")) {
                return getCssWebResourceResponseFromAsset();
            } else {
                return super.shouldInterceptRequest(view, url);
            }
        }

        /**
         * Return WebResourceResponse with CSS markup from a String. 
         */
        @SuppressWarnings("deprecation")
        private WebResourceResponse getCssWebResourceResponseFromString() {
            return getUtf8EncodedCssWebResourceResponse(new ByteArrayInputStream("body { background-color: #F781F3; }".getBytes()));
        }

        /**
         * Return WebResourceResponse with CSS markup from an asset (e.g. "assets/style.css"). 
         */
        private WebResourceResponse getCssWebResourceResponseFromAsset() {
            try {
                return getUtf8EncodedCssWebResourceResponse(getAssets().open("style.css"));
            } catch (IOException e) {
                return null;
            }
        }

        /**
         * Return WebResourceResponse with CSS markup from a raw resource (e.g. "raw/style.css"). 
         */
        private WebResourceResponse getCssWebResourceResponseFromRawResource() {
            return getUtf8EncodedCssWebResourceResponse(getResources().openRawResource(R.raw.style));
        }

        private WebResourceResponse getUtf8EncodedCssWebResourceResponse(InputStream data) {
            return new WebResourceResponse("text/css", "UTF-8", data);
        }

    });

    webview.loadUrl("http://stackoverflow.com");

拦截加载css文件并返回自己的WebResourceResponse,其中包含你想要加载的数据。

请注意,此方法需要API级别11

如果您想在Android 2.x上实现类似的功能,则可以尝试使用前面提到的shouldOverrideUrlLoading(WebView view,String url)来避免加载页面,手动获取页面内容,将css文件的引用替换为自己的,并最终调用loadData(String data,String mimeType,String encoding)(或loadDataWithBaseURL(String baseUrl,String data,String mimeType,String encoding,String historyUrl))在WebView上,将处理后的html内容作为字符串传递。

之前:

Before

之后:

After


抱歉回复晚了——工作很忙。我整理了一下代码,并添加了一堆示例,说明如何使用“shouldInterceptRequest”方法。使用这些示例,我没有遇到任何问题,可以捕获SO的CSS文件,而不是加载包含更多内容的自己的文件。请参见添加的屏幕截图 :) 我建议您在自己的代码中设置断点,并尝试按照我上面的示例重新加载资产。 - MH.
MH非常感谢。我的本地CSS现在已经完美地与shouldinterceptmethod一起工作了。但是现在我遇到了一个问题,就是如何将特定的JavaScript(CSS和jQuery的组合)附加到Webview中。你有什么想法吗?谢谢。 - androdio
你可以按照这里所述的方式,可能会注入一些JavaScript代码。然而,如果您计划对文档进行大量修改,我建议最好先获取源代码,以任何您想要的方式进行修改(最好使用众多HTML/XML解析器之一),最后将其提供给WebView。这是您完全控制文档源的唯一方法... - MH.
你好,我尝试使用 shouldOverrideUrlLoading 来替换 URL,但在 2.3 版本上无法正常工作。 - atian25
@MH,是的,我尝试过了,但shouldOverrideUrlLoading()没有触发。 - atian25
显示剩余7条评论

3

这对你可能也很有用。它从特定文件夹读取文件,如果请求的文件名与其相同,则使用资产文件夹中的文件而不是网络上的文件。

    //get list of files of specific asset folder
    private ArrayList listAssetFiles(String path) {

        List myArrayList = new ArrayList();
        String [] list;
        try {
            list = getAssets().list(path);
            for(String f1 : list){
                myArrayList.add(f1);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (ArrayList) myArrayList;
    }

    //get mime type by url
    public String getMimeType(String url) {
        String type = null;
        String extension = MimeTypeMap.getFileExtensionFromUrl(url);
        if (extension != null) {
            if (extension.equals("js")) {
                return "text/javascript";
            }
            else if (extension.equals("woff")) {
                return "application/font-woff";
            }
            else if (extension.equals("woff2")) {
                return "application/font-woff2";
            }
            else if (extension.equals("ttf")) {
                return "application/x-font-ttf";
            }
            else if (extension.equals("eot")) {
                return "application/vnd.ms-fontobject";
            }
            else if (extension.equals("svg")) {
                return "image/svg+xml";
            }
            type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
        }
        return type;
    }

    //return webresourceresponse
    public WebResourceResponse loadFilesFromAssetFolder (String folder, String url) {
        List myArrayList = listAssetFiles(folder);
        for (Object str : myArrayList) {
            if (url.contains((CharSequence) str)) {
                try {
                    Log.i(TAG2, "File:" + str);
                    Log.i(TAG2, "MIME:" + getMimeType(url));
                    return new WebResourceResponse(getMimeType(url), "UTF-8", getAssets().open(String.valueOf(folder+"/" + str)));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    //@TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @SuppressLint("NewApi")
    @Override
    public WebResourceResponse shouldInterceptRequest(final WebView view, String url) {
        //Log.i(TAG2, "SHOULD OVERRIDE INIT");
        //String url = webResourceRequest.getUrl().toString();
        String extension = MimeTypeMap.getFileExtensionFromUrl(url);
        //I have some folders for files with the same extension
        if (extension.equals("css") || extension.equals("js") || extension.equals("img")) {
            return loadFilesFromAssetFolder(extension, url);
        }
        //more possible extensions for font folder
        if (extension.equals("woff") || extension.equals("woff2") || extension.equals("ttf") || extension.equals("svg") || extension.equals("eot")) {
            return loadFilesFromAssetFolder("font", url);
        }

        return null;
    }

shouldInterceptRequest方法已被弃用,如果使用新的方法,则会出现“不得为空”的错误。 - Md Imran Choudhury
不错的解决方案,但最好放完整的代码... webview.setWebViewClient(new WebViewClient() {... - Eyni Kave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接