Android Development
WebView
setWebViewClient
setWebChromeClient
Mobile App Development

What's the difference between setWebViewClient vs. setWebChromeClient?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

setWebViewClient and setWebChromeClient are not two ways to solve the same problem. They handle different parts of WebView behavior, and many real Android apps need both because one manages page navigation while the other manages browser-style UI features.

What WebViewClient Handles

WebViewClient is responsible for navigation-related behavior inside the WebView. This is where you keep links inside the app, observe page completion, react to load errors, and enforce URL handling rules.

kotlin
1webView.webViewClient = object : WebViewClient() {
2    override fun shouldOverrideUrlLoading(
3        view: WebView?,
4        request: WebResourceRequest?
5    ): Boolean {
6        val url = request?.url?.toString().orEmpty()
7
8        return if (url.startsWith("myapp://")) {
9            handleDeepLink(url)
10            true
11        } else {
12            false
13        }
14    }
15
16    override fun onPageFinished(view: WebView?, url: String?) {
17        progressBar.visibility = View.GONE
18    }
19
20    override fun onReceivedError(
21        view: WebView?,
22        request: WebResourceRequest?,
23        error: WebResourceError?
24    ) {
25        showErrorUi(error?.description?.toString() ?: "Load failed")
26    }
27}

If you do not set a WebViewClient, many links may open in the external browser instead of staying in your app's WebView.

What WebChromeClient Handles

WebChromeClient is responsible for browser-chrome behavior. That includes progress updates, page titles, JavaScript dialogs, permission prompts, file chooser flows, and custom full-screen content such as video.

kotlin
1webView.webChromeClient = object : WebChromeClient() {
2    override fun onProgressChanged(view: WebView?, newProgress: Int) {
3        progressBar.progress = newProgress
4    }
5
6    override fun onReceivedTitle(view: WebView?, title: String?) {
7        supportActionBar?.title = title
8    }
9
10    override fun onJsAlert(
11        view: WebView?,
12        url: String?,
13        message: String?,
14        result: JsResult?
15    ): Boolean {
16        AlertDialog.Builder(this@MainActivity)
17            .setMessage(message)
18            .setPositiveButton("OK") { _, _ -> result?.confirm() }
19            .setCancelable(false)
20            .show()
21        return true
22    }
23}

If page titles never update or JavaScript dialogs do not appear, the missing piece is often WebChromeClient.

Real Apps Commonly Use Both Together

These two clients are complementary, not competing.

kotlin
1webView.settings.javaScriptEnabled = true
2webView.settings.domStorageEnabled = true
3
4webView.webViewClient = AppWebViewClient()
5webView.webChromeClient = AppWebChromeClient()
6
7webView.loadUrl("https://example.com")

A simple way to remember the split is:

  • 'WebViewClient handles page transport and navigation'
  • 'WebChromeClient handles browser-style UI callbacks'

Once that boundary is clear, the callback placement becomes much easier to remember.

Practical Examples

If you need to intercept a custom URL scheme such as myapp://checkout, that belongs in WebViewClient.

If the web page needs a file chooser for an upload field, that belongs in WebChromeClient.

kotlin
1override fun onShowFileChooser(
2    webView: WebView?,
3    filePathCallback: ValueCallback<Array<Uri>>?,
4    fileChooserParams: FileChooserParams?
5): Boolean {
6    launchPicker(filePathCallback)
7    return true
8}

Trying to solve upload handling in WebViewClient will not work because it is the wrong layer of responsibility.

Security and Policy Belong Closer to WebViewClient

Navigation policy, SSL behavior, and request trust decisions usually belong in WebViewClient.

kotlin
1override fun onReceivedSslError(
2    view: WebView?,
3    handler: SslErrorHandler?,
4    error: SslError?
5) {
6    handler?.cancel()
7}

That is another clue about the separation: request-level behavior lives closer to WebViewClient, while UI-like browser behavior lives closer to WebChromeClient.

Avoid Overriding Too Much

It is possible to break WebView behavior by intercepting everything. For example, always returning true from shouldOverrideUrlLoading without loading the URL yourself can stop normal navigation entirely.

The goal is to override only the behavior your app actually needs. Let the WebView handle the rest.

Common Pitfalls

A common mistake is expecting WebViewClient to handle JavaScript dialogs, upload prompts, or progress callbacks. Those belong to WebChromeClient.

Another is forgetting to set WebViewClient and then being surprised when taps open the external browser.

Developers also sometimes intercept every URL aggressively and accidentally block ordinary navigation. Override selectively.

Finally, do not weaken SSL handling just to make a broken site load during testing. That shortcut can become a production security problem very quickly.

Summary

  • 'WebViewClient handles navigation, loading lifecycle, and request-related behavior.'
  • 'WebChromeClient handles browser-style UI features such as titles, dialogs, and progress.'
  • Most nontrivial WebView integrations need both on the same view.
  • Put URL policy in WebViewClient and UI callbacks in WebChromeClient.
  • Knowing the responsibility boundary makes WebView debugging much easier.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.