javaandroidkotlinwebviewokhttp

Android WebView is loading the URL content in plain HTML when I override shouldInterceptRequest for posting data with OkHttpClient


I need to POST to a URL in a WebView with headers and a form body. I have added the below code but WebView loads the page content in plain HTML.

Can anyone please help me resolve this issue? Any help is highly appreciated.

Thanks in advance

binding.webView.apply { 
settings.javaScriptEnabled = true 
settings.domStorageEnabled = true 
settings.allowContentAccess = true 
settings.loadWithOverviewMode = true 
settings.javaScriptCanOpenWindowsAutomatically = true 
settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        
webViewClient = object : WebViewClient() {
           override fun shouldOverrideUrlLoading(
                view: WebView?,
                request: WebResourceRequest?
            ): Boolean {
                showLoadingView()
                return false
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                hideLoadingView()
            }

            override fun shouldInterceptRequest(
                view: WebView?,
                request: WebResourceRequest
            ): WebResourceResponse {
                return postDataOkHttpClient(supportCenter)
            }
        }
        loadUrl(supportCenter?.consumerUrl ?: "")
}

private fun postDataOkHttpClient(supportCenter: SupportCenter?): WebResourceResponse {    

    val client = OkHttpClient()

    val mediaType = "application/json; charset=utf-8".toMediaType()

    val jsonObject = JSONObject()
    jsonObject.put("token", supportCenter?.token ?: "")
    jsonObject.put("lang", supportCenter?.lang ?: "")
    jsonObject.put("channel", supportCenter?.channel ?: "")

    val body = jsonObject.toString().toRequestBody(mediaType)

    val request = Request.Builder()
        .url(supportCenter?.consumerUrl ?: "")
        .addHeader("Authorization", supportCenter?.authToken ?: "")
        .addHeader("Content-Type", "application/x-www-form-urlencoded")
        .post(body)
        .build()

    val response = client.newCall(request).execute()

    return WebResourceResponse(
        getMimeType(supportCenter?.consumerUrl ?: ""),
        response.header("content-encoding", "utf-8"),
        response.body!!.byteStream()
    )
}

private fun getMimeType(url: String?): String? { 
            var type: String? = null val 
            extension = MimeTypeMap.getFileExtensionFromUrl(url) 
            if (extension != null) { 
            when (extension) { 
            "js" -> { 
                return "text/javascript" 
            }            
            "woff" -> {
                return "application/font-woff"
            }

            "woff2" -> {
                return "application/font-woff2"
            }

            "ttf" -> {
                return "application/x-font-ttf"
            }

            "eot" -> {
                return "application/vnd.ms-fontobject"
            }

            "svg" -> {
                return "image/svg+xml"
            }

            else -> type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
        }
    }
    return type
}

I have tried different settings for the WebView hence, you see so many settings applied, and set settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL as well and I tried with and without mimeType in WebResourceResponse. But it doesn't seem to load the page properly.


Solution

  • Using OkHttpClient: You are using OkHttpClient to make a network request inside shouldInterceptRequest method. This approach is incorrect because shouldInterceptRequest is meant to intercept and modify the request, not to make new network requests. Instead, you should modify the original request passed as a parameter.

    webViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(
        view: WebView?,
        request: WebResourceRequest?
    ): Boolean {
        showLoadingView()
        return false
    }
    
    override fun onPageFinished(view: WebView?, url: String?) {
        super.onPageFinished(view, url)
        hideLoadingView()
    }
    
    override fun shouldInterceptRequest(
        view: WebView?,
        request: WebResourceRequest
    ): WebResourceResponse? {
        if (request.url.toString() == supportCenter?.consumerUrl) {
            val postData = "token=${supportCenter?.token}&lang=${supportCenter?.lang}&channel=${supportCenter?.channel}"
            val postDataBytes = postData.toByteArray(Charsets.UTF_8)
    
            val headers = HashMap<String, String>()
            headers["Authorization"] = supportCenter?.authToken ?: ""
            headers["Content-Type"] = "application/x-www-form-urlencoded"
    
            // Execute the request asynchronously
            OkHttpClient().newCall(Request.Builder()
                .url(request.url.toString())
                .headers(Headers.of(headers))
                .post(RequestBody.create(MediaType.parse("text/plain; charset=utf-8"), postData))
                .build()
            ).enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    e.printStackTrace()
                    // Handle failure if needed
                }
    
                override fun onResponse(call: Call, response: Response) {
                    val contentType = response.header("Content-Type")
                    val charset = response.body?.contentType()?.charset(Charsets.UTF_8) ?: Charsets.UTF_8
                    val data = response.body?.string() ?: ""
    
                    // Convert response data to input stream
                    val inputStream = ByteArrayInputStream(data.toByteArray(charset))
    
                    // Pass the response data to WebView
                    view?.post {
                        view.loadDataWithBaseURL(null, data, contentType, "UTF-8", null)
                    }
                }
            })
    
            // Return null to indicate that the WebView should not load the original request
            return null
        }
        return null
    }
    

    }