I am using Jetpack Compose and have a WebView
wrapped in a AndroidView
composable that looks like the following:
AndroidView(modifier = modifier, factory = { context ->
WebView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
webViewClient = WebViewClient()
settings.javaScriptEnabled = true
}
}, update = { webView -> webView.loadUrl(url) })
In the legacy way, we could add a OnBackPressedDispatcher
to the Activity
to intercept the back press and navigate inside the WebView
by accessing it via viewBinding for example with functions of the WebView
like goBack()
and to check if you can go back with canGoBack()
.
But how can we achieve the same with this Jetpack Compose approach?
There doesn't seem to be anything wrong with assigning the WebView to an external var so that's what I've done here.
var backEnabled by remember { mutableStateOf(false) }
var webView: WebView? = null
AndroidView(
modifier = modifier,
factory = { context ->
WebView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
webViewClient = object : WebViewClient() {
override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
backEnabled = view.canGoBack()
}
}
settings.javaScriptEnabled = true
loadUrl(url)
webView = this
}
}, update = {
webView = it
})
BackHandler(enabled = backEnabled) {
webView?.goBack()
}
The WebViewClient
listens for onPageStarted
which checks if the WebView can navigate backwards and then updates backEnabled
. This causes a recomposition which toggles the BackHandler on and off.
I've also moved loadUrl
out of the update
function and into factory
because update is called every time there's a recomposition whereas factory is only called the once. This may or may not be relevant based on your implementation.