Muszę dodać niestandardowe nagłówki do KAŻDEGO żądania pochodzącego z WebView. Wiem, że loadURL
ma parametr for extraHeaders
, ale są one stosowane tylko do początkowego żądania. Wszystkie kolejne żądania nie zawierają nagłówków. Przyjrzałem się wszystkim zastąpieniom w programie WebViewClient
, ale nic nie pozwala na dodawanie nagłówków do żądań zasobów - onLoadResource(WebView view, String url)
. Każda pomoc byłaby cudowna.
Dzięki, Ray
java
android
webkit
android-webview
Promień
źródło
źródło
Odpowiedzi:
Próbować
Aby dodać nagłówki do żądań ładowania zasobów, utwórz niestandardowy WebViewClient i zastąp:
API 24+: WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) or WebResourceResponse shouldInterceptRequest(WebView view, String url)
źródło
view.loadUrl("http://www.facebook.com", extraHeaders)
, jest wiele żądań zasobów, takich jak'http://static.fb.com/images/logo.png'
itp., Które są wysyłane z widoku internetowego. W przypadku tych żądań dodatkowe nagłówki nie są dodawane. I shouldOverrideUrlLoading nie jest wywoływana podczas takich żądań zasobów. Wywoływana jest funkcja zwrotna „OnLoadResource”, ale w tym momencie nie ma możliwości ustawienia nagłówków.WebViewClient.shouldInterceptRequest(android.webkit.WebView view, java.lang.String url)
Check out, aby uzyskać więcej.shouldInterceptRequest
metody, czy możesz wyjaśnić, w jaki sposób?Będziesz musiał przechwycić każde żądanie za pomocą WebViewClient.shouldInterceptRequest
Przy każdym przechwyceniu będziesz musiał pobrać adres URL, samodzielnie wykonać to żądanie i zwrócić strumień treści:
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);
Jeśli minimalnym celem API jest poziom 21 , możesz użyć nowego shouldInterceptRequest, który zapewnia dodatkowe informacje o żądaniu (takie jak nagłówki) zamiast tylko adresu URL.
źródło
public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request)
zamiast tego, znajdź więcej tutajMoże moja odpowiedź dość późno, ale obejmuje API poniżej i powyżej 21 poziomu.
Aby dodać nagłówki, powinniśmy przechwycić każde żądanie i utworzyć nowe z wymaganymi nagłówkami.
Musimy więc nadpisać metodę shouldInterceptRequest wywołaną w obu przypadkach: 1. dla API do poziomu 21; 2. dla poziomu 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; } } });
Jeśli typ odpowiedzi powinien zostać przetworzony, możesz go zmienić
return new WebResourceResponse( null, // <- Change here response.header("content-encoding", "utf-8"), response.body().byteStream() );
do
return new WebResourceResponse( getMimeType(url), // <- Change here response.header("content-encoding", "utf-8"), response.body().byteStream() );
i dodaj metodę
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; }
źródło
Jak wspomniano wcześniej, możesz to zrobić:
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);
Przetestowałem to i dalej za pomocą kontrolera MVC, który rozszerzyłem atrybut autoryzacji, aby sprawdzić nagłówek i nagłówek tam jest.
źródło
To działa dla mnie:
Najpierw musisz stworzyć metodę, która zwróci twoje nagłówki, które chcesz dodać do żądania:
private Map<String, String> getCustomHeaders() { Map<String, String> headers = new HashMap<>(); headers.put("YOURHEADER", "VALUE"); return headers; }
Po drugie, musisz utworzyć 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; } }; }
Dodaj WebViewClient do swojego WebView:
Mam nadzieję że to pomoże.
źródło
loadUrl(String url, Map<String, String> additionalHttpHeaders)
oznacza dodawanie dodatkowych nagłówkówPowinieneś być w stanie kontrolować wszystkie swoje nagłówki, pomijając loadUrl i pisząc własną loadPage przy użyciu HttpURLConnection Java. Następnie użyj loadData webview, aby wyświetlić odpowiedź.
Nie ma dostępu do nagłówków udostępnianych przez Google. Są w wywołaniu JNI, głęboko w źródle WebView.
źródło
Oto implementacja wykorzystująca 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 } }
Zauważ, że to nie działa w przypadku żądań POST, ponieważ WebResourceRequest nie dostarcza danych POST. Istnieje biblioteka danych żądania - WebViewClient, która wykorzystuje obejście iniekcji JavaScript do przechwytywania danych POST.
źródło
To zadziałało dla mnie. Utwórz WebViewClient w ten sposób poniżej i ustaw klienta internetowego na swój widok sieciowy. Musiałem użyć webview.loadDataWithBaseURL, ponieważ moje adresy URL (w mojej treści) nie miały adresu podstawowego, ale tylko względne adresy URL. Prawidłowy adres URL zostanie uzyskany tylko wtedy, gdy za pomocą loadDataWithBaseURL ustawiono podstawowy adresurl.
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; } } }; }
źródło
Możesz użyć tego:
@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; }
źródło
Przeszedłem przez ten sam problem i rozwiązałem.
Jak wspomniano wcześniej, musisz utworzyć niestandardowy WebViewClient i zastąpić metodę shouldInterceptRequest.
WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
Ta metoda powinna wywołać webView.loadUrl podczas zwracania „pustej” odpowiedzi WebResourceResponse.
Coś takiego:
@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); }
źródło
Użyj tego:
webView.getSettings().setUserAgentString("User-Agent");
źródło