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?