wake-up-neo.com

Hinzufügen benutzerdefinierter Header zu WebView-Ressourcenanforderungen - Android

Ich muss zu JEDER Anfrage, die aus der WebView kommt, benutzerdefinierte Header hinzufügen. Ich weiß, dass loadURL den Parameter für extraHeaders hat, diese werden jedoch nur auf die ursprüngliche Anforderung angewendet. Alle nachfolgenden Anforderungen enthalten nicht die Kopfzeilen. Ich habe mir alle Überschreibungen in WebViewClient angesehen, aber nichts erlaubt das Hinzufügen von Headern zu Ressourcenanforderungen - onLoadResource(WebView view, String url). Jede Hilfe wäre wunderbar.

Danke, Ray 

72
Ray

Versuchen 

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

Nehmen Sie zum Hinzufügen von Headern zu Ressourcenladeanforderungen benutzerdefinierten WebViewClient vor und überschreiben:

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

Sie müssen jede Anfrage mit WebViewClient.shouldInterceptRequest abfangen.

Bei jedem Abfangen müssen Sie die URL übernehmen, diese Anforderung selbst stellen und den Inhaltsstrom zurückgeben:

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);

Wenn Ihr Mindest-API-Ziel Level 21 ist, können Sie das neue shouldInterceptRequest verwenden, das Ihnen zusätzliche Anforderungsinformationen (z. B. Header) anstelle nur der URL gibt.

29
Martin Konecny

Wie bereits erwähnt, können Sie Folgendes tun:

 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);

Ich habe dies getestet und mit einem MVC-Controller das Berechtigungsattribut erweitert, um den Header und den Header dort zu überprüfen. 

17
leeroya

Vielleicht ist meine Antwort ziemlich spät, aber sie deckt API unter und über 21 ab.

Um Header hinzuzufügen, müssen wir jede Anfrage abfangen und eine neue mit den erforderlichen Headern erstellen.

In beiden Fällen müssen wir die shouldInterceptRequest -Methode überschreiben: 1. für API bis Level 21; 2. für 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;
            }

        }
   });

Wenn der Antworttyp verarbeitet werden soll, können Sie dies ändern

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

zu

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

und Methode hinzufügen

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

Das funktioniert für mich:

  1. Zuerst müssen Sie eine Methode erstellen, die Ihre -Header zurückgibt, die Sie der Anfrage hinzufügen möchten:

    private Map<String, String> getCustomHeaders()
    {
        Map<String, String> headers = new HashMap<>();
        headers.put("YOURHEADER", "VALUE");
        return headers;
    }
    
  2. Zweitens müssen Sie WebViewClient erstellen:

    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. Fügen Sie Ihrem WebView WebViewClient hinzu:

    webView.setWebViewClient(getWebViewClient());
    

Hoffe das hilft.

6
eltray

Sie sollten in der Lage sein, alle Ihre Header zu steuern, indem Sie loadUrl überspringen und Ihre eigene loadPage mit Javas HttpURLConnection schreiben. Verwenden Sie dann die loadData des Webview, um die Antwort anzuzeigen.

Es gibt keinen Zugriff auf die von Google bereitgestellten Header. Sie befinden sich in einem JNI-Aufruf, tief in der WebView-Quelle.

4
R Earle Harris

Das hat bei mir funktioniert. Erstellen Sie einen WebViewClient wie folgt und stellen Sie den Webclient auf Ihre Webansicht ein. Ich musste webview.loadDataWithBaseURL verwenden, da meine URLs (in meinem Inhalt) nicht die Basis-URL hatten, sondern nur relative URLs. Sie erhalten die URL nur dann korrekt, wenn ein Basiswert mithilfe von loadDataWithBaseURL festgelegt ist.

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

}
1
Shekar

Ich kam durch dasselbe Problem und löste mich.

Wie bereits erwähnt, müssen Sie Ihren benutzerdefinierten WebViewClient erstellen und die shouldInterceptRequest-Methode überschreiben. 

WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)

Diese Methode sollte eine webView.loadUrl ausgeben, während eine "leere" WebResourceResponse zurückgegeben wird.

Etwas wie das:

@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);
}
0
Francesco

Hier ist eine Implementierung mit 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
    }
}

Beachten Sie, dass dies nicht für POST - Anforderungen funktioniert, da WebResourceRequest keine POST - Daten bereitstellt. Es gibt eine Request Data - WebViewClient-Bibliothek , die eine JavaScript-Injection-Workaround zum Abfangen von POST -Daten verwendet.