Easy way to customize the request headers and UserAgent in WkWebView and WebView on iOS and Android.

Even though native app development is popular, there are still so many apps that use WebView as a part of the native app to show some detail to the end user. In such cases, we might need to add custom header values to the WebView request. I’m going to show how to add a custom header in WebView on iOS and Android.

Let’s see how to add a custom header in WKWebView on iOS

Customizing iOS WKWebView headers

A WKWebView object is a platform-native view that you use to incorporate web content seamlessly into your app’s UI. A web view supports a full web-browsing experience and presents HTML, CSS, and JavaScript content alongside your app’s native views. Let’s see how to customize UserAgent value in WKWebView

Customizing UserAgent in WKWebView

To illustrate a practical scenario, let us consider the case where it becomes necessary to incorporate an application name and version number within the UserAgent string. In such instances, the utilization of the applicationNameForUserAgent property within the WKWebViewConfiguration is imperative, as demonstrated in the following manner:

let webConfig = WKWebViewConfiguration()
webConfig.applicationNameForUserAgent = "MyApp/2.2.1"
mWebView = WKWebView(frame: UIScreen.main.bounds, configuration: webConfig)

This will add the custom value along with the current UserAgent string.

Customizing header in WKWebView

To include custom request headers within the WKWebView, it is essential to follow a series of steps. Firstly, the registration for the navigationDelegate of the WKWebView is required.

mWebView.navigationDelegate = self

Subsequently, the implementation of the webView: decidePolicyForNavigationAction: decisionHandler: delegate method becomes necessary. This particular delegate method is invoked for every API request initiated by the WKWebView. Consequently, it is vital to identify the specific API or endpoint that necessitates the addition of the custom header, and proceed to incorporate the custom header in the manner exemplified below:

func loadWebPage(url: URL)  {
     print("URL to Load: "+url.absoluteString)
     var customRequest = URLRequest(url: url)
     customRequest.setValue("some value", forHTTPHeaderField: kCustomHeader)
     mWebView.load(customRequest)
 }

// MARK: - WKNavigationDelegate
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping
        (WKNavigationActionPolicy) -> Void) {
     guard let url = navigationAction.request.url else {
        decisionHandler(.cancel)
        return
     }
     if url.absoluteString == "about:blank" {
        decisionHandler(.cancel)
        return
     }
     else if navigationAction.request.value(forHTTPHeaderField: kCustomHeader) != nil || url.absoluteString.hasPrefix(kBaseURL) == false {
         // not a GET or already a custom request - continue
         decisionHandler(.allow)
         return
     }
     decisionHandler(.cancel)
     loadWebPage(url: url)
 }

Allow the API if its already has the custom header and load those URL which doesn’t have the custom header as shown above.

This way we can add the custom header in the WKWebView. Ok, Let’s look at how to add the custom header in WebView on Android.

Customizing Android WebView headers

WebView objects allow us to display web content as part of your activity layout, but lack some of the features of fully-developed browsers. A WebView is useful when you need increased control over the UI and advanced configuration options that will allow you to embed web pages in a specially-designed environment for the app.

Customizing header in Android WebView

To add the custom header and UserAgent in the WebView, we need to use shouldInterceptRequest callback of WebViewClient as shown below. We need to use our custom network stack in order to add any custom value to the network request. In my case i’m using HttpURLConnection as a network stack we can use any other network frameworks as well.

 private void setupWebView(){
    WebView mWebView = (WebView) findViewById(R.id.webView);
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);

    WebViewClient wvc = new WebViewClient(){
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
            final String method = request.getMethod();
            final String url = request.getUrl().toString();
            String ext = MimeTypeMap.getFileExtensionFromUrl(url);
            String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext);

            try {
                HttpURLConnection conn = (HttpURLConnection)new URL(url).openConnection();
                conn.setRequestMethod(method);
                conn.setRequestProperty("Custom-Header", "hello");
                conn.setRequestProperty("User-Agent","MyApp/2.2.1");//For adding custom UserAgent
                conn.setDoInput(true);
                conn.setUseCaches(false);

                Map<String, String> responseHeaders = convertResponseHeaders(conn.getHeaderFields());

                return new WebResourceResponse(
                        mime,
                        conn.getContentEncoding(),
                        conn.getResponseCode(),
                        conn.getResponseMessage(),
                        responseHeaders,
                        conn.getInputStream()
                );

            } catch (Exception e) {
                Log.e("BMPUtil", "shouldInterceptRequest: " + e);
            }
            return null;
        }
    };
    mWebView.setWebViewClient(wvc);
    mWebView.loadUrl("https://swiss.com/");
}

private Map<String, String> convertResponseHeaders(Map<String, List<String>> headers) {
    Map<String, String> responseHeaders = new HashMap<>();
    for (Map.Entry<String, List<String>> item : headers.entrySet()) {
        List<String> values = new ArrayList<String>();
        for (String headerVal : item.getValue()) {
            values.add(headerVal);
        }
        String value = TextUtils.join(",", values);
        responseHeaders.put(item.getKey(), value);
    }
    return responseHeaders;
}

This way we can add any custom headers in all request which flows through the WebView.

By using this method we can easily customize WebView headers in iOS and Android. I hope this helps to simplify the process.

Happy Coding…

Written By
Fareeth John

I’m working as a Sr. Solution Architect in Akamai Technologies. I have more than 12 years of experience in the Mobile app development industry. Worked on different technologies like VR, Augmented reality, OTT, and IoT in iOS, Android, flutter, and other cross-platform apps. Have worked on 45+ apps from scratch which are in the AppStore and PlayStore. My knowledge of mobile development including design/architecting solutions, app development, knowledge around backend systems,  cloud computing, CDN, Test Automation, CI/CD, Frida Pentesting, and finding mobile app vulnerabilities

Leave a Reply

Your email address will not be published. Required fields are marked *