【问题标题】:Intercept and override HTTP requests from WebView拦截并覆盖来自 WebView 的 HTTP 请求
【发布时间】:2011-06-14 10:23:13
【问题描述】:

我的应用程序中有一个 WebView,其中打开了一些站点(始终相同,它是我自己的页面)。该站点有一些从远程主机加载一些图像的 JS 代码。

我想拦截对此类图像的请求(通过 URL 模式)并返回我自己的内容(即另一张图像),或者根据内部应用程序逻辑保持请求不变。

有可能吗?

编辑:问题的当前状态...

WebView 能够设置WebViewClient(如 Axarydax 所述)。 WebViewClient有两个有用的方法

  • shouldOverrideUrlLoading
  • onLoadResource

shouldOverrideUrlLoading 能够拦截任何 URL 加载,如果加载是由页面交互触发的(即点击页面上的链接,WebView.loadURL("") 不会触发此方法)。它还可以通过返回 false 来取消 URL 加载。这种方法不可用,因为它无法拦截页面资源的加载(而我需要拦截的图像就是这样的页面资源)。

onLoadResource 每次加载页面资源(和图像!感谢 Jessyjones)时都会触发,但无法取消。这使得这种方法也不适合我的任务。

【问题讨论】:

    标签: android android-webview webviewclient


    【解决方案1】:

    试试这个,我在个人 wiki 类应用中使用过它:

    webView.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (url.startsWith("foo://")) {
                // magic
                return true;
            }
            return false;
        }
    });
    

    【讨论】:

    • 好的,这是拦截呼叫的方式(顺便说一下,如果我的页面加载图像而不是完全重新加载,它会触发吗?),但是我如何为拦截的呼叫提供响应由我的 Java 代码生成?
    • 您可以使用 WebView 的 loadData() 方法将一些 html 推入其中。用法:webView.loadData("...", "text/html", "utf-8");
    • 不适合。通过 loadData 加载的静态内容无法访问通过网络加载的其他内容。作为一种解决方法,可以使用 loadData("javascript:....")(与一些“客户端”代码交互)。如果为每个页面资源(确切地说是内容图像)调用 shouldOverrideUrlLoading,这可能是一个很好且合适的方法。但它没有。
    • 如果你使用url.endsWith("jpg")呢?您只需要使用它来处理 jpeg、gif 和 png...然后,Azarydax 提供的代码应该可以工作,不是吗?
    • 自 API 24 起,此版本的 shouldOverrideUrlLoading 已弃用。要解决这个问题,请参阅以下问题:stackoverflow.com/q/36484074/56285
    【解决方案2】:

    看起来 API 级别 11 支持您的需求。见WebViewClient.shouldInterceptRequest()

    【讨论】:

    • 请注意!如果您拦截了浏览器检索图像(或可能是任何资源)的尝试,然后返回null(意味着让 WebView 继续检索图像),任何未来对该资源的请求都可能只是进入缓存并且不会触发shouldInterceptRequest()。如果要拦截每个图像请求,则需要禁用缓存或(我所做的)调用WebView.clearCache(true)
    • 我正在尝试添加自定义 cookie 和其他标题。知道怎么做吗?
    • 自 API 24 起,采用 String urlshouldInterceptRequest 版本已被弃用。要解决这个问题,请参阅以下问题:stackoverflow.com/q/36484074/56285(关于弃用,shouldInterceptRequest 类似于shouldOverrideUrlLoading。)
    • 这适用于问题中的特定情况,但不适用于所有网络调用,因为 shouldInterceptRequest() 方法不提供 POST 请求的数据。
    【解决方案3】:

    据我所知,shouldOverrideUrlLoading 不是为图像调用而是为超链接调用...我认为合适的方法是

    @Override public void onLoadResource(WebView view, String url)

    为 webview 加载的每个资源(图像、样式表、脚本)调用此方法,但由于它是无效的,我还没有找到一种方法来更改该 url 并替换它以便它加载本地资源...

    【讨论】:

    • 是的,通过这种方法,我加载了所有的 url(一个根目录,以及那里的所有资源)。但问题仍然是 - 如何覆盖加载=(我对如何替换图像内容有一些想法,但仍然不清楚如何覆盖原始调用。
    【解决方案4】:

    这是我用于我的应用的解决方案。

    我有几个带有 css / js / img anf 字体文件的资产文件夹。

    应用程序获取所有文件名并查看是否请求了具有此名称的文件。如果是,它会从资产文件夹中加载它。

    //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;
            }
    

    【讨论】:

      【解决方案5】:

      你没有提到 API 版本,但是从 API 11 开始就有了方法WebViewClient.shouldInterceptRequest

      也许这会有所帮助?

      【讨论】:

      【解决方案6】:

      最终的解决方案是嵌入一个简单的 http 服务器,在环回的“秘密”端口上监听。然后你可以用http://localhost:123/.../mypic.jpg之类的东西替换匹配的图像src URL

      【讨论】:

        【解决方案7】:

        这可能会有所帮助:

        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            String url = request.getUrl().toString();
            WebResourceResponse response = super.shouldInterceptRequest(view, request);
            // load native js
            if (url != null && url.contains(INJECTION_TOKEN/* scheme define */)) {
        
                response = new WebResourceResponse(
                        "text/javascript",
                        "utf-8",
                        loadJsInputStream(url, JsCache.getJsFilePath(path) /* InputStream */));
            }
            return response;
        }
        

        【讨论】:

        猜你喜欢
        • 2014-10-29
        • 2021-08-07
        • 1970-01-01
        • 2018-03-30
        • 1970-01-01
        • 2017-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多