拦截并覆盖来自 WebView 的 HTTP 请求

发布于 2024-10-13 12:07:53 字数 688 浏览 3 评论 0原文

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

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

可以这样做吗?

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

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

  • shouldOverrideUrlLoading
  • onLoadResource

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

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

I have a WebView in my application in which some site is opened (always the same, it is my own page). The site has some JS code that loads some images from the remote host.

I want to intercept requests to such images (by URL pattern) and give back my own content (i.e. another image), or leave request untouched depending on internal application logic.

Is it possible to do that?

EDIT: The current state of the question...

WebView has the ability to set a WebViewClient (as noted by Axarydax). WebViewClient have two useful methods

  • shouldOverrideUrlLoading
  • onLoadResource

shouldOverrideUrlLoading is able to intercept any URL loading, if loading is triggered by page interaction (i.e. link on a page is clicked, WebView.loadURL("") isn't triggering this method). It is also able to cancel URL loading by returning false. This approach isn't usable, cause' it is not able to intercept loading of page resources (and images, what I need to intercept, is such a page resource).

onLoadResource is triggering every time that page resource (and images! thx to Jessyjones) are loading, but there is no way to cancel that. That makes this method not suitable for my task also.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

甜嗑 2024-10-20 12:07:53

试试这个,我在个人类似维基的应用程序中使用过它:

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

Try this, I've used it in a personal wiki-like app:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (url.startsWith("foo://")) {
            // magic
            return true;
        }
        return false;
    }
});
深居我梦 2024-10-20 12:07:53

看起来 API 级别 11 已支持您的需求。请参阅 <代码>WebViewClient.shouldInterceptRequest()

It looks like API level 11 has support for what you need. See WebViewClient.shouldInterceptRequest().

暗藏城府 2024-10-20 12:07:53

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

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

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

As far as I know, shouldOverrideUrlLoading is not called for images but rather for hyperlinks... I think the appropriate method is

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

This method is called for every resource (image, styleesheet, script) that's loaded by the webview, but since it's a void, I haven't found a way to change that url and replace it so that it loads a local resource ...

我不是你的备胎 2024-10-20 12:07:53

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

我有几个包含 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;
        }

Here is my solution I use for my app.

I have several asset folder with css / js / img anf font files.

The application gets all filenames and looks if a file with this name is requested. If yes, it loads it from asset folder.

//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;
        }
亢潮 2024-10-20 12:07:53

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

也许这会有所帮助?

You don't mention the API version, but since API 11 there's the method WebViewClient.shouldInterceptRequest

Maybe this could help?

薯片软お妹 2024-10-20 12:07:53

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

An ultimate solution would be to embed a simple http server listening on your 'secret' port on loopback. Then you can substitute the matched image src URL with something like http://localhost:123/.../mypic.jpg

时光无声 2024-10-20 12:07:53

这可能有帮助:

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

This may helps:

@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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文