将自定义标头添加到 WebView 资源请求 - android

发布于 2024-12-07 23:37:53 字数 255 浏览 1 评论 0原文

我需要为来自 WebView 的每个请求添加自定义标头。我知道 loadURLextraHeaders 的参数,但这些仅适用于初始请求。所有后续请求都不包含标头。我查看了 WebViewClient 中的所有覆盖,但没有任何内容允许向资源请求添加标头 - onLoadResource(WebView view, String url)。任何帮助都会很棒。

谢谢, 射线

I need to add custom headers to EVERY request coming from the WebView. I know loadURL has the parameter for extraHeaders, but those are only applied to the initial request. All subsequent requests do not contain the headers. I have looked at all overrides in WebViewClient, but nothing allows for adding headers to resource requests - onLoadResource(WebView view, String url). Any help would be wonderful.

Thanks,
Ray

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

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

发布评论

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

评论(13

蓝眸 2024-12-14 23:37:53

尝试

loadUrl(String url, Map<String, String> extraHeaders)

将标头添加到资源加载请求中,制作自定义 WebViewClient 并覆盖:

API 24+:
WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
or
WebResourceResponse shouldInterceptRequest(WebView view, String url)

Try

loadUrl(String url, Map<String, String> extraHeaders)

For adding headers to resources loading requests, make custom WebViewClient and override:

API 24+:
WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
or
WebResourceResponse shouldInterceptRequest(WebView view, String url)
甜点 2024-12-14 23:37:53

您需要使用 拦截每个请求WebViewClient.shouldInterceptRequest

每次拦截时,您都需要获取 url,自己发出此请求,然后返回内容流:

WebViewClient wvc = new WebViewClient() {
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

        try {
            DefaultHttpClient client = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(url);
            httpGet.setHeader("MY-CUSTOM-HEADER", "header value");
            httpGet.setHeader(HttpHeaders.USER_AGENT, "custom user-agent");
            HttpResponse httpReponse = client.execute(httpGet);

            Header contentType = httpReponse.getEntity().getContentType();
            Header encoding = httpReponse.getEntity().getContentEncoding();
            InputStream responseInputStream = httpReponse.getEntity().getContent();

            String contentTypeValue = null;
            String encodingValue = null;
            if (contentType != null) {
                contentTypeValue = contentType.getValue();
            }
            if (encoding != null) {
                encodingValue = encoding.getValue();
            }
            return new WebResourceResponse(contentTypeValue, encodingValue, responseInputStream);
        } catch (ClientProtocolException e) {
            //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        } catch (IOException e) {
             //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        }
    }
}

Webview wv = new WebView(this);
wv.setWebViewClient(wvc);

如果您的最低 API 目标是级别 21,您可以使用新的shouldInterceptRequest 为您提供附加请求信息(例如标头)而不仅仅是 URL。

You will need to intercept each request using WebViewClient.shouldInterceptRequest

With each interception, you will need to take the url, make this request yourself, and return the content stream:

WebViewClient wvc = new WebViewClient() {
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

        try {
            DefaultHttpClient client = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(url);
            httpGet.setHeader("MY-CUSTOM-HEADER", "header value");
            httpGet.setHeader(HttpHeaders.USER_AGENT, "custom user-agent");
            HttpResponse httpReponse = client.execute(httpGet);

            Header contentType = httpReponse.getEntity().getContentType();
            Header encoding = httpReponse.getEntity().getContentEncoding();
            InputStream responseInputStream = httpReponse.getEntity().getContent();

            String contentTypeValue = null;
            String encodingValue = null;
            if (contentType != null) {
                contentTypeValue = contentType.getValue();
            }
            if (encoding != null) {
                encodingValue = encoding.getValue();
            }
            return new WebResourceResponse(contentTypeValue, encodingValue, responseInputStream);
        } catch (ClientProtocolException e) {
            //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        } catch (IOException e) {
             //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        }
    }
}

Webview wv = new WebView(this);
wv.setWebViewClient(wvc);

If your minimum API target is level 21, you can use the new shouldInterceptRequest which gives you additional request information (such as headers) instead of just the URL.

香草可樂 2024-12-14 23:37:53

也许我的回复很晚了,但它涵盖了 API 低于高于 21 级别。

要添加标头,我们应该拦截每个请求并使用所需的标头创建新的请求

因此,我们需要重写在这两种情况下调用的 shouldInterceptRequest 方法:
1. API 至 21 级;
2. 对于 API 级别 21+

    webView.setWebViewClient(new WebViewClient() {

        // Handle API until level 21
        @SuppressWarnings("deprecation")
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

            return getNewResponse(url);
        }

        // Handle API 21+
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

            String url = request.getUrl().toString();

            return getNewResponse(url);
        }

        private WebResourceResponse getNewResponse(String url) {

            try {
                OkHttpClient httpClient = new OkHttpClient();

                Request request = new Request.Builder()
                        .url(url.trim())
                        .addHeader("Authorization", "YOU_AUTH_KEY") // Example header
                        .addHeader("api-key", "YOUR_API_KEY") // Example header
                        .build();

                Response response = httpClient.newCall(request).execute();

                return new WebResourceResponse(
                        null,
                        response.header("content-encoding", "utf-8"),
                        response.body().byteStream()
                );

            } catch (Exception e) {
                return null;
            }

        }
   });

如果应处理响应类型,您可以更改

        return new WebResourceResponse(
                null, // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

        return new WebResourceResponse(
                getMimeType(url), // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

并添加方法

        private String getMimeType(String url) {
            String type = null;
            String extension = MimeTypeMap.getFileExtensionFromUrl(url);

            if (extension != null) {

                switch (extension) {
                    case "js":
                        return "text/javascript";
                    case "woff":
                        return "application/font-woff";
                    case "woff2":
                        return "application/font-woff2";
                    case "ttf":
                        return "application/x-font-ttf";
                    case "eot":
                        return "application/vnd.ms-fontobject";
                    case "svg":
                        return "image/svg+xml";
                }

                type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
            }

            return type;
        }

Maybe my response quite late, but it covers API below and above 21 level.

To add headers we should intercept every request and create new one with required headers.

So we need to override shouldInterceptRequest method called in both cases:
1. for API until level 21;
2. for API level 21+

    webView.setWebViewClient(new WebViewClient() {

        // Handle API until level 21
        @SuppressWarnings("deprecation")
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

            return getNewResponse(url);
        }

        // Handle API 21+
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

            String url = request.getUrl().toString();

            return getNewResponse(url);
        }

        private WebResourceResponse getNewResponse(String url) {

            try {
                OkHttpClient httpClient = new OkHttpClient();

                Request request = new Request.Builder()
                        .url(url.trim())
                        .addHeader("Authorization", "YOU_AUTH_KEY") // Example header
                        .addHeader("api-key", "YOUR_API_KEY") // Example header
                        .build();

                Response response = httpClient.newCall(request).execute();

                return new WebResourceResponse(
                        null,
                        response.header("content-encoding", "utf-8"),
                        response.body().byteStream()
                );

            } catch (Exception e) {
                return null;
            }

        }
   });

If response type should be processed you could change

        return new WebResourceResponse(
                null, // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

to

        return new WebResourceResponse(
                getMimeType(url), // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

and add method

        private String getMimeType(String url) {
            String type = null;
            String extension = MimeTypeMap.getFileExtensionFromUrl(url);

            if (extension != null) {

                switch (extension) {
                    case "js":
                        return "text/javascript";
                    case "woff":
                        return "application/font-woff";
                    case "woff2":
                        return "application/font-woff2";
                    case "ttf":
                        return "application/x-font-ttf";
                    case "eot":
                        return "application/vnd.ms-fontobject";
                    case "svg":
                        return "image/svg+xml";
                }

                type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
            }

            return type;
        }
听风吹 2024-12-14 23:37:53

如前所述,您可以执行此操作:

 WebView  host = (WebView)this.findViewById(R.id.webView);
 String url = "<yoururladdress>";

 Map <String, String> extraHeaders = new HashMap<String, String>();
 extraHeaders.put("Authorization","Bearer"); 
 host.loadUrl(url,extraHeaders);

我对此进行了测试,并使用 MVC 控制器进行了测试,我扩展了授权属性来检查标头,标头就在那里。

As mentioned before, you can do this:

 WebView  host = (WebView)this.findViewById(R.id.webView);
 String url = "<yoururladdress>";

 Map <String, String> extraHeaders = new HashMap<String, String>();
 extraHeaders.put("Authorization","Bearer"); 
 host.loadUrl(url,extraHeaders);

I tested this and on with a MVC Controller that I extended the Authorize Attribute to inspect the header and the header is there.

梦过后 2024-12-14 23:37:53

这对我有用:

  1. 首先您需要创建方法,该方法将返回您的
    您要添加到请求的标头:

    私有地图获取自定义标题()
    {
        映射<字符串,字符串> headers = new HashMap<>();
        headers.put("YOURHEADER", "VALUE");
        返回标头;
    }
    
  2. 其次您需要创建 WebViewClient:

    私有 WebViewClient getWebViewClient()
    {
    
        返回新的 WebViewClient()
        {
    
        @覆盖
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        公共布尔shouldOverrideUrlLoading(WebView视图,WebResourceRequest请求)
        {
            view.loadUrl(request.getUrl().toString(), getCustomHeaders());
            返回真;
        }
    
        @覆盖
        公共布尔shouldOverrideUrlLoading(WebView视图,字符串url)
        {
            view.loadUrl(url, getCustomHeaders());
            返回真;
        }
    };
    }
    
  3. 将 WebViewClient 添加到您的 WebView:

    webView.setWebViewClient(getWebViewClient());
    

希望这会有所帮助。

This works for me:

  1. First you need to create method, which will be returns your
    headers you want to add to request:

    private Map<String, String> getCustomHeaders()
    {
        Map<String, String> headers = new HashMap<>();
        headers.put("YOURHEADER", "VALUE");
        return headers;
    }
    
  2. Second you need to create WebViewClient:

    private WebViewClient getWebViewClient()
    {
    
        return new WebViewClient()
        {
    
        @Override
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
        {
            view.loadUrl(request.getUrl().toString(), getCustomHeaders());
            return true;
        }
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url)
        {
            view.loadUrl(url, getCustomHeaders());
            return true;
        }
    };
    }
    
  3. Add WebViewClient to your WebView:

    webView.setWebViewClient(getWebViewClient());
    

Hope this helps.

赴月观长安 2024-12-14 23:37:53

以下是使用 HttpUrlConnection 的实现:

class CustomWebviewClient : WebViewClient() {
    private val charsetPattern = Pattern.compile(".*?charset=(.*?)(;.*)?$")

    override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
        try {
            val connection: HttpURLConnection = URL(request.url.toString()).openConnection() as HttpURLConnection
            connection.requestMethod = request.method
            for ((key, value) in request.requestHeaders) {
                connection.addRequestProperty(key, value)
            }

            connection.addRequestProperty("custom header key", "custom header value")

            var contentType: String? = connection.contentType
            var charset: String? = null
            if (contentType != null) {
                // some content types may include charset => strip; e. g. "application/json; charset=utf-8"
                val contentTypeTokenizer = StringTokenizer(contentType, ";")
                val tokenizedContentType = contentTypeTokenizer.nextToken()

                var capturedCharset: String? = connection.contentEncoding
                if (capturedCharset == null) {
                    val charsetMatcher = charsetPattern.matcher(contentType)
                    if (charsetMatcher.find() && charsetMatcher.groupCount() > 0) {
                        capturedCharset = charsetMatcher.group(1)
                    }
                }
                if (capturedCharset != null && !capturedCharset.isEmpty()) {
                    charset = capturedCharset
                }

                contentType = tokenizedContentType
            }

            val status = connection.responseCode
            var inputStream = if (status == HttpURLConnection.HTTP_OK) {
                connection.inputStream
            } else {
                // error stream can sometimes be null even if status is different from HTTP_OK
                // (e. g. in case of 404)
                connection.errorStream ?: connection.inputStream
            }
            val headers = connection.headerFields
            val contentEncodings = headers.get("Content-Encoding")
            if (contentEncodings != null) {
                for (header in contentEncodings) {
                    if (header.equals("gzip", true)) {
                        inputStream = GZIPInputStream(inputStream)
                        break
                    }
                }
            }
            return WebResourceResponse(contentType, charset, status, connection.responseMessage, convertConnectionResponseToSingleValueMap(connection.headerFields), inputStream)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return super.shouldInterceptRequest(view, request)
    }

    private fun convertConnectionResponseToSingleValueMap(headerFields: Map<String, List<String>>): Map<String, String> {
        val headers = HashMap<String, String>()
        for ((key, value) in headerFields) {
            when {
                value.size == 1 -> headers[key] = value[0]
                value.isEmpty() -> headers[key] = ""
                else -> {
                    val builder = StringBuilder(value[0])
                    val separator = "; "
                    for (i in 1 until value.size) {
                        builder.append(separator)
                        builder.append(value[i])
                    }
                    headers[key] = builder.toString()
                }
            }
        }
        return headers
    }
}

请注意,这不适用于 POST 请求,因为 WebResourceRequest 不提供 POST 数据。有一个 请求数据 - WebViewClient 库,它使用 JavaScript 注入解决方法来拦截 POST 数据。

Here is an implementation using HttpUrlConnection:

class CustomWebviewClient : WebViewClient() {
    private val charsetPattern = Pattern.compile(".*?charset=(.*?)(;.*)?$")

    override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
        try {
            val connection: HttpURLConnection = URL(request.url.toString()).openConnection() as HttpURLConnection
            connection.requestMethod = request.method
            for ((key, value) in request.requestHeaders) {
                connection.addRequestProperty(key, value)
            }

            connection.addRequestProperty("custom header key", "custom header value")

            var contentType: String? = connection.contentType
            var charset: String? = null
            if (contentType != null) {
                // some content types may include charset => strip; e. g. "application/json; charset=utf-8"
                val contentTypeTokenizer = StringTokenizer(contentType, ";")
                val tokenizedContentType = contentTypeTokenizer.nextToken()

                var capturedCharset: String? = connection.contentEncoding
                if (capturedCharset == null) {
                    val charsetMatcher = charsetPattern.matcher(contentType)
                    if (charsetMatcher.find() && charsetMatcher.groupCount() > 0) {
                        capturedCharset = charsetMatcher.group(1)
                    }
                }
                if (capturedCharset != null && !capturedCharset.isEmpty()) {
                    charset = capturedCharset
                }

                contentType = tokenizedContentType
            }

            val status = connection.responseCode
            var inputStream = if (status == HttpURLConnection.HTTP_OK) {
                connection.inputStream
            } else {
                // error stream can sometimes be null even if status is different from HTTP_OK
                // (e. g. in case of 404)
                connection.errorStream ?: connection.inputStream
            }
            val headers = connection.headerFields
            val contentEncodings = headers.get("Content-Encoding")
            if (contentEncodings != null) {
                for (header in contentEncodings) {
                    if (header.equals("gzip", true)) {
                        inputStream = GZIPInputStream(inputStream)
                        break
                    }
                }
            }
            return WebResourceResponse(contentType, charset, status, connection.responseMessage, convertConnectionResponseToSingleValueMap(connection.headerFields), inputStream)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return super.shouldInterceptRequest(view, request)
    }

    private fun convertConnectionResponseToSingleValueMap(headerFields: Map<String, List<String>>): Map<String, String> {
        val headers = HashMap<String, String>()
        for ((key, value) in headerFields) {
            when {
                value.size == 1 -> headers[key] = value[0]
                value.isEmpty() -> headers[key] = ""
                else -> {
                    val builder = StringBuilder(value[0])
                    val separator = "; "
                    for (i in 1 until value.size) {
                        builder.append(separator)
                        builder.append(value[i])
                    }
                    headers[key] = builder.toString()
                }
            }
        }
        return headers
    }
}

Note that this does not work for POST requests because WebResourceRequest doesn't provide POST data. There is a Request Data - WebViewClient library which uses a JavaScript injection workaround for intercepting POST data.

始于初秋 2024-12-14 23:37:53

您应该能够通过跳过 loadUrl 并使用 Java 的 HttpURLConnection 编写自己的 loadPage 来控制所有标头。然后使用 webview 的 loadData 显示响应。

无法访问 Google 提供的标头。它们位于 WebView 源深处的 JNI 调用中。

You should be able to control all your headers by skipping loadUrl and writing your own loadPage using Java's HttpURLConnection. Then use the webview's loadData to display the response.

There is no access to the headers which Google provides. They are in a JNI call, deep in the WebView source.

傲鸠 2024-12-14 23:37:53

这对我有用。像下面这样创建 WebViewClient 并将 webclient 设置为您的 webview。我必须使用 webview.loadDataWithBaseURL 因为我的网址(在我的内容中)没有基本网址,而只有相对网址。只有当使用 loadDataWithBaseURL 设置了 baseurl 时,您才能正确获取 url。

public WebViewClient getWebViewClientWithCustomHeader(){
    return new WebViewClient() {
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            try {
                OkHttpClient httpClient = new OkHttpClient();
                com.squareup.okhttp.Request request = new com.squareup.okhttp.Request.Builder()
                        .url(url.trim())
                        .addHeader("<your-custom-header-name>", "<your-custom-header-value>")
                        .build();
                com.squareup.okhttp.Response response = httpClient.newCall(request).execute();

                return new WebResourceResponse(
                        response.header("content-type", response.body().contentType().type()), // You can set something other as default content-type
                        response.header("content-encoding", "utf-8"),  // Again, you can set another encoding as default
                        response.body().byteStream()
                );
            } catch (ClientProtocolException e) {
                //return null to tell WebView we failed to fetch it WebView should try again.
                return null;
            } catch (IOException e) {
                //return null to tell WebView we failed to fetch it WebView should try again.
                return null;
            }
        }
    };

}

This worked for me. Create WebViewClient like this below and set the webclient to your webview. I had to use webview.loadDataWithBaseURL as my urls (in my content) did not have the baseurl but only relative urls. You will get the url correctly only when there is a baseurl set using loadDataWithBaseURL.

public WebViewClient getWebViewClientWithCustomHeader(){
    return new WebViewClient() {
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            try {
                OkHttpClient httpClient = new OkHttpClient();
                com.squareup.okhttp.Request request = new com.squareup.okhttp.Request.Builder()
                        .url(url.trim())
                        .addHeader("<your-custom-header-name>", "<your-custom-header-value>")
                        .build();
                com.squareup.okhttp.Response response = httpClient.newCall(request).execute();

                return new WebResourceResponse(
                        response.header("content-type", response.body().contentType().type()), // You can set something other as default content-type
                        response.header("content-encoding", "utf-8"),  // Again, you can set another encoding as default
                        response.body().byteStream()
                );
            } catch (ClientProtocolException e) {
                //return null to tell WebView we failed to fetch it WebView should try again.
                return null;
            } catch (IOException e) {
                //return null to tell WebView we failed to fetch it WebView should try again.
                return null;
            }
        }
    };

}
风吹短裙飘 2024-12-14 23:37:53

shouldInterceptRequest 无法拦截 request.body
我建议您在 werview.loadUrl 之前重置 userAgent。

喜欢:
webview.settings.userAgentString += " key1/value1 key2/value2"

shouldInterceptRequest could not intercept request.body.
I recommend you reset userAgent before werview.loadUrl.

like:
webview.settings.userAgentString += " key1/value1 key2/value2"

情何以堪。 2024-12-14 23:37:53

您可以尝试我的解决方案来解决该问题,虽然我承认它可能并不普遍适用,但事实证明它可以有效满足我的特定要求,特别是在处理大量不触发 WebViewClient 回调的 JavaScript 获取调用时。

长话短说:

要将自定义标头添加到每个 WebView HTTP 请求中,您可以注入 java 脚本代码来覆盖您自己的 WebViewClient 中的 window.fetch 行为。

下面是详细实现

1. 创建您的自定义WebViewClient

class CustomHeaderWebViewClient(headerValue: String) : WebViewClient() { }

在这个自定义WebViewClient 中,您可以传递您想要注入HTTP 标头的headerValue。

2. 定义 JS 注入代码

创建一个存储 JavaScript 注入代码的属性。此代码将修改 window.fetch 方法以包含自定义标头:

private val authHeaderInjection = """
            (function() {
                const originalFetch = window.fetch;
                window.fetch = function(input, init) {
                    init = init || {};
                    init.headers = init.headers || {};
                    init.headers['My-Header'] = '$headerValue';
                    return originalFetch.apply(this, arguments);
                };
            })();
        """.trimIndent()

3. 重写 onPageStarted 方法

您需要重写 onPageStarted 方法以在每个导航上执行 JavaScript 注入:

override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
    view?.evaluateJavascript(authHeaderInjection) { Timber.d(it) }
    super.onPageStarted(view, url, favicon)
}

注意:取决于 的实现WebView的内容,你可以选择不同的回调。

4. 最后,不要忘记为您的 WebView 设置自定义 WebViewClient。

注意:请注意,根据您的要求,在使用 webview.loadUrl(url, yourHeaders) 时,您可能仍需要手动添加其他自定义标头。

最终代码:

import android.graphics.Bitmap
import android.webkit.WebView
import android.webkit.WebViewClient
import timber.log.Timber

class CustomHeaderWebViewClient(headerValue: String) : WebViewClient() {
    private val authHeaderInjection = """
            (function() {
                const originalFetch = window.fetch;
                window.fetch = function(input, init) {
                    init = init || {};
                    init.headers = init.headers || {};
                    init.headers['My-Header'] = '${headerValue}';
                    return originalFetch.apply(this, arguments);
                };
            })();
        """.trimIndent()

    override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
        view?.evaluateJavascript(authHeaderInjection) { Timber.d(it) }
        super.onPageStarted(view, url, favicon)
    }
}

You can try my solution for the issue, and while I acknowledge that it may not be universally applicable, it has proven effective in meeting my specific requirements, particularly when dealing with a significant number of JavaScript fetch calls that do not trigger WebViewClient callbacks.

Long story short:

To add custom headers into every WebView HTTP request, you can inject java script code that overrides window.fetch behavior in your own WebViewClient.

The following is a detailed implementation

1. Create your custom WebViewClient

class CustomHeaderWebViewClient(headerValue: String) : WebViewClient() { }

In this custom WebViewClient, you can pass the headerValue that you want to inject into HTTP headers.

2. Define JS-injection code

Create a property that stores your JavaScript injection code. This code will modify the window.fetch method to include the custom header:

private val authHeaderInjection = """
            (function() {
                const originalFetch = window.fetch;
                window.fetch = function(input, init) {
                    init = init || {};
                    init.headers = init.headers || {};
                    init.headers['My-Header'] = '$headerValue';
                    return originalFetch.apply(this, arguments);
                };
            })();
        """.trimIndent()

3. Override onPageStarted Method

You need to override the onPageStarted method to execute the JavaScript injection on each navigation:

override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
    view?.evaluateJavascript(authHeaderInjection) { Timber.d(it) }
    super.onPageStarted(view, url, favicon)
}

Note: Depending on the implementation of the WebView's content, you can choose different callbacks.

4. Finally, don't forget to set your custom WebViewClient for your WebView.

Note: Please note that you may still need to manually add other custom headers when using webview.loadUrl(url, yourHeaders) as per your requirements.

Final code:

import android.graphics.Bitmap
import android.webkit.WebView
import android.webkit.WebViewClient
import timber.log.Timber

class CustomHeaderWebViewClient(headerValue: String) : WebViewClient() {
    private val authHeaderInjection = """
            (function() {
                const originalFetch = window.fetch;
                window.fetch = function(input, init) {
                    init = init || {};
                    init.headers = init.headers || {};
                    init.headers['My-Header'] = '${headerValue}';
                    return originalFetch.apply(this, arguments);
                };
            })();
        """.trimIndent()

    override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
        view?.evaluateJavascript(authHeaderInjection) { Timber.d(it) }
        super.onPageStarted(view, url, favicon)
    }
}
偏爱你一生 2024-12-14 23:37:53

你可以使用这个:

@Override

 public boolean shouldOverrideUrlLoading(WebView view, String url) {

                // Here put your code
                Map<String, String> map = new HashMap<String, String>();
                map.put("Content-Type","application/json");
                view.loadUrl(url, map);
                return false;

            }

You can use this:

@Override

 public boolean shouldOverrideUrlLoading(WebView view, String url) {

                // Here put your code
                Map<String, String> map = new HashMap<String, String>();
                map.put("Content-Type","application/json");
                view.loadUrl(url, map);
                return false;

            }
就是爱搞怪 2024-12-14 23:37:53

我遇到了同样的问题并解决了。

如前所述,您需要创建自定义 WebViewClient 并重写 shouldInterceptRequest 方法。

WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)

该方法应发出 webView.loadUrl,同时返回“空”WebResourceResponse。

像这样的事情:

@Override
public boolean shouldInterceptRequest(WebView view, WebResourceRequest request) {

    // Check for "recursive request" (are yor header set?)
    if (request.getRequestHeaders().containsKey("Your Header"))
        return null;

    // Add here your headers (could be good to import original request header here!!!)
    Map<String, String> customHeaders = new HashMap<String, String>();
    customHeaders.put("Your Header","Your Header Value");
    view.loadUrl(url, customHeaders);

    return new WebResourceResponse("", "", null);
}

I came accross the same problem and solved.

As said before you need to create your custom WebViewClient and override the shouldInterceptRequest method.

WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)

That method should issue a webView.loadUrl while returning an "empty" WebResourceResponse.

Something like this:

@Override
public boolean shouldInterceptRequest(WebView view, WebResourceRequest request) {

    // Check for "recursive request" (are yor header set?)
    if (request.getRequestHeaders().containsKey("Your Header"))
        return null;

    // Add here your headers (could be good to import original request header here!!!)
    Map<String, String> customHeaders = new HashMap<String, String>();
    customHeaders.put("Your Header","Your Header Value");
    view.loadUrl(url, customHeaders);

    return new WebResourceResponse("", "", null);
}
忆梦 2024-12-14 23:37:53

使用这个:

webView.getSettings().setUserAgentString("User-Agent");

Use this:

webView.getSettings().setUserAgentString("User-Agent");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文