I have business logic outside of composable creation, which needs to be able to feed data to webview -> javascript. However, the webview shouldn't be saved, as stated here:
Note: Constructing the view in the AndroidView viewBlock is the best practice. Do not hold or remember a direct view reference outside AndroidView. https://developer.android.com/jetpack/compose/interop/interop-apis
How can I call webview's evaluateJavascript() outside of the composable creating the webview?
This is the code (lateinit as an example of what doesn't work):
@SuppressLint("SetJavaScriptEnabled")
@Composable
fun WebPageScreen(urlToRender: String, someViewModel: SomeViewModel) {
AndroidView(factory = {
WebView(it).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
webViewClient = WebViewClient()
settings.javaScriptEnabled = true
addJavascriptInterface(someViewModel.createWebAppInterface(context), "Android")
loadUrl(urlToRender)
someViewModel.webViewObj = this //<<--- won't work like this.
}, update = {
it.loadUrl(urlToRender)
})
}
class SomeViewModel(application: Application): AndroidViewModel(application) {
lateinit var webViewObj: WebView // <<--"This field leaks a context object"
fun callJs() {
webViewObj.evaluateJavascript("updateSomething(123)",null)
}
fun createWebAppInterface(mContext: Context) : WebAppInterface {
return WebAppInterface(mContext)
}
inner class WebAppInterface(private val mContext: Context) {
@JavascriptInterface
fun webViewCallJs() {
callJs()
}
}
}
Here the idea is, that callJs() could be called both from webView (e.g. a HTML UI button), and from within business logic (SomeViewModel). How can we achieve this when webview cannot be remembered, but we should be able call its function from outside?
In the accompanist-webview library, they've used a local webview state like below:
var webView by remember { mutableStateOf<WebView?>(null) }
AndroidView(
factory = { context ->
WebView(context).apply {
...
}.also { webView = it }
},
) {
...
}
You can then use webView.post{ webview.evaluateJavaScript() } to execute JS functions
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With