Saya perlu menambahkan tajuk khusus ke SETIAP permintaan yang datang dari WebView. Saya tahu loadURL
memiliki parameter untuk extraHeaders
, tetapi itu hanya diterapkan pada permintaan awal. Semua permintaan berikutnya tidak mengandung header. Saya telah melihat semua timpaan WebViewClient
, tetapi tidak ada yang memungkinkan untuk menambahkan header ke permintaan sumber daya - onLoadResource(WebView view, String url)
. Bantuan apa pun akan sangat bagus.
Terima kasih, Ray
java
android
webkit
android-webview
sinar
sumber
sumber
Jawaban:
Mencoba
Untuk menambahkan header ke permintaan pemuatan resource, buat WebViewClient kustom dan timpa:
API 24+: WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) or WebResourceResponse shouldInterceptRequest(WebView view, String url)
sumber
view.loadUrl("http://www.facebook.com", extraHeaders)
, ada beberapa permintaan sumber daya seperti'http://static.fb.com/images/logo.png'
dll yang dikirim dari webiew. Untuk permintaan ini, header tambahan tidak ditambahkan. Dan shouldOverrideUrlLoading tidak dipanggil selama permintaan sumber daya seperti itu. Callback 'OnLoadResource' dipanggil, tetapi belum ada cara untuk menyetel header pada saat ini.WebViewClient.shouldInterceptRequest(android.webkit.WebView view, java.lang.String url)
Lihat API untuk selengkapnya.shouldInterceptRequest
metode ini, dapatkah Anda menjelaskan caranya?Anda perlu menghentikan setiap permintaan menggunakan WebViewClient.shouldInterceptRequest
Dengan setiap intersepsi, Anda perlu mengambil url, membuat permintaan ini sendiri, dan mengembalikan aliran konten:
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);
Jika target API minimum Anda adalah level 21 , Anda bisa menggunakan shouldInterceptRequest baru yang memberi Anda informasi permintaan tambahan (seperti header), bukan hanya URL.
sumber
public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request)
sebagai gantinya temukan lebih banyak di siniMungkin respon saya agak terlambat, tapi mencakup API di bawah dan di atas level 21.
Untuk menambahkan tajuk, kita harus menghentikan setiap permintaan dan membuat yang baru dengan tajuk yang diperlukan.
Jadi kita perlu mengganti metode shouldInterceptRequest yang dipanggil dalam kedua kasus: 1. untuk API hingga level 21; 2. untuk 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; } } });
Jika jenis respons harus diproses, Anda dapat mengubahnya
return new WebResourceResponse( null, // <- Change here response.header("content-encoding", "utf-8"), response.body().byteStream() );
untuk
return new WebResourceResponse( getMimeType(url), // <- Change here response.header("content-encoding", "utf-8"), response.body().byteStream() );
dan tambahkan metode
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; }
sumber
Seperti yang disebutkan sebelumnya, Anda dapat melakukan ini:
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);
Saya menguji ini dan melanjutkan dengan MVC Controller yang saya tambahkan Atribut Otorisasi untuk memeriksa header dan header ada di sana.
sumber
Ini bekerja untuk saya:
Pertama, Anda perlu membuat metode, yang akan mengembalikan header yang ingin Anda tambahkan ke permintaan:
private Map<String, String> getCustomHeaders() { Map<String, String> headers = new HashMap<>(); headers.put("YOURHEADER", "VALUE"); return headers; }
Kedua, Anda perlu membuat 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; } }; }
Tambahkan WebViewClient ke WebView Anda:
Semoga ini membantu.
sumber
loadUrl(String url, Map<String, String> additionalHttpHeaders)
berarti menambahkan tajuk tambahanAnda harus dapat mengontrol semua header Anda dengan melewatkan loadUrl dan menulis loadPage Anda sendiri menggunakan HttpURLConnection Java. Kemudian gunakan loadData tampilan web untuk menampilkan respons.
Tidak ada akses ke header yang disediakan Google. Mereka berada dalam panggilan JNI, jauh di dalam sumber WebView.
sumber
Berikut adalah implementasi menggunakan 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 } }
Perhatikan bahwa ini tidak berfungsi untuk permintaan POST karena WebResourceRequest tidak menyediakan data POST. Ada Request Data - pustaka WebViewClient yang menggunakan solusi injeksi JavaScript untuk mencegat data POST.
sumber
Ini berhasil untuk saya. Buat WebViewClient seperti ini di bawah ini dan setel webclient ke tampilan web Anda. Saya harus menggunakan webview.loadDataWithBaseURL karena url saya (dalam konten saya) tidak memiliki baseurl tetapi hanya url relatif. Anda akan mendapatkan url dengan benar hanya jika ada kumpulan baseurl yang menggunakan 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; } } }; }
sumber
Anda dapat menggunakan ini:
@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; }
sumber
Saya menemukan masalah yang sama dan menyelesaikannya.
Seperti yang dikatakan sebelumnya, Anda perlu membuat WebViewClient kustom dan mengganti metode shouldInterceptRequest.
WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
Metode itu harus mengeluarkan webView.loadUrl sambil mengembalikan WebResourceResponse "kosong".
Sesuatu seperti ini:
@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); }
sumber
Gunakan ini:
webView.getSettings().setUserAgentString("User-Agent");
sumber