How I Almost Put an iframe into a WebView
Listening to JavaScript events on 3rd party webpages
Snap Click by Foundry is licenced under Creative Commons CC0
Here’s a situation. You need to load a third party URL into a view, and listen to events on the page. That shouldn’t be too hard, right? Android has WebViews we can use, and a way to interface with JavaScript events. We’ll assume we are already in an Activity
with a WebView
instantiated. Let’s start building it.
private fun loadWebView(webView: WebView, url: String) = with(webView) { loadUrl(url) }
We already know we’ll need JavaScript enabled so we have something to listen to.
private fun loadWebView(webView: WebView, url: String) = with(webView) { settings.javaScriptEnabled = true loadUrl(url) }
That was easy. Next, we need to listen to the JavaScript events on the WebView
. We will include a method to our WebAppInterface
that we can call from the JavaScript on the page. Here’s how the Android docs guide us to do that.
public class WebAppInterface { @JavascriptInterface fun handleMyEvent(jsonString: String) { val data: JSONObject = JSONObject(jsonString) // Do stuff with event data } }
private fun loadWebView(webView: WebView, url: String) = with(webView) { settings.javaScriptEnabled = true addJavascriptInterface(WebAppInterface(), "MyJSInterface") loadUrl(url) }
Then, on the webpage we’re loading, we add this script:
<script type="text/javascript"> function HandleMyEvents(event) { MyJSInterface.handleMyEvent(JSON.stringify(event.data)); } window.addEventListener("message", HandleMyEvents, false); </script>
Not too difficult. But here’s where the issue comes in. In this example we don’t have access to the JavaScript on the webpage to make it call the Android web interface. How could we add our own JavaScript to listen to the events? This is how I almost used an iframe
. By loading HTML into the WebView
with an iframe
, and some custom JavaScript, I could hook into those events and forward it to the interface.
private fun loadWebView(webView: WebView, url: String) = with(webView) { addJavascriptInterface(WebAppInterface(), "MyJSInterface") loadData(htmlString(url), "text/html", "utf-8") }
htmlString()
would look like:
private fun htmlString(url: String): String { return """ <iframe src='$url'></iframe> $listenerScript """ }
And the listener script as described above:
private val listenerScript: String get() = """ <script type='text/javascript'> function HandleMyEvents(event) { MyJSInterface.handleMyEvent(JSON.stringify(event.data)); } window.addEventListener('message', HandleMyEvents, false); </script> """
But do we really want to use an iframe
? No, not usually.
Thankfully, I came across a better solution (of course I stumbled on this when I was looking for something else). So intead of using an iframe
we can inject the JavaScript right into the WebView
! Before we load in the URL we first set the WebChromeClient
.
private fun loadWebView(webView: WebView, url: String) = with(webView) { settings.javaScriptEnabled = true addJavascriptInterface(WebAppInterface(), "MyJSInterface") setWebChromeClient(WebChromeClient()) loadUrl(url) }
Then, we also need to set the WebViewClient
. We will override the onPageFinished()
method of the WebViewClient
to load our JavaScript. The JavaScript is the same as above.
private fun loadWebView(webView: WebView, url: String) = with(webView) { settings.javaScriptEnabled = true addJavascriptInterface(WebAppInterface(), "MyJSInterface") setWebChromeClient(WebChromeClient()) setWebViewClient(object : WebViewClient() { override fun onPageFinished(view: WebView, url: String) { view.loadUrl(listenerScript) } }) loadUrl(url) }
And there we go! We can now listen to those events in our Android code. I don’t often use WebView
s, and it would not have been fun to combine it with an iframe
, so I’m glad I was able to find that solution.
Comments
Free download the official Kodi TV App with step by step guide.
This post is really helpful to know. Thank you very much!Movierulz
I see this too. I always thought that Chrome Assignment Writing Help | primeassignment.com would replace WebView, but in Q WebView is back.