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