Communication from WebView to Native iOS/ Android App
One of the most common use case in native mobile apps development is sending and receiving data from WebView to native and vice versa. There are couple of misconception while handling this scenario in iOS / Android. Let us deep dive into reality.
Many mobile applications have common features like login with third party vendor in which, native layer should interact with embedded webview. Or payment gateways which sends back success/failure/token etc to native to proceed. Which ever the scenario , interaction between native layer and webview is essential.
Point #1:
Is it really hard to make the flow functional while receiving callbacks from WebView to Native layer? 💻 🤔
Point #2:
Is sending data from Native to WebView or other way around a mess?🤔
But the fact is , both platforms provide convenient way for this type of communication. This tutorial shows how to achieve this in iOS and Android. For demonstration , I have included webview in both samples with a green background with input field and button. Similarly native has input field and button in white background. Data send from native will replace input field in web and vice-versa.🧐
Either load an Html page, which will be sent from server to mobile , or load a common Html file saved in app cache. For demonstration , lets have Html file in both platforms saved locally and loaded in WebView.
Respective Sources: iOS Github Source and Android Github Source
1 — iOS:
1.1 To receive data from webview.We will use WKScriptMessageHandler protocol. This will help us to add script message handler from native with specific name of the message handler.
var mNativeToWebHandler : String = “jsMessageHandler”mWebKitView.configuration.userContentController.add(self, name: mNativeToWebHandler)
After this, we can use the function userContentController to track specific handler.
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {if message.name == mNativeToWebHandler {mEdtTxt.text = message.body as? String}}
Now we need to have function in HTML JS Script to send the data from HTML page. Which will be like the below. Keep the name of message handler as same in JS Script as well.
function sendMessage(){var valueToSend = //your data from htmlwindow.webkit.messageHandlers.jsMessageHandler.postMessage(valueToSend);}
1.2 For sending data from Native to WebView, we can use WKWebView’s evaluateJavaScript method from native.
var data = //your data from nativeself.mWebKitView.evaluateJavaScript(“document.getElementById(‘inputField’).value=’\(data)’”)
And the HTML component will be
<input id="inputField" style="height:50px;width:300px;font-size:20pt;" type="text" value="">
This will directly replace the corresponding element in webview.😊👏 🎉
2 — Android:
2.1 To receive data from webview ,we can create an interface, which will enable webview to connect the native layer and pass data.
function sendMessage() {
var valueReceived = document.getElementById("inputField").value;
JSBridge.showMessageInNative(valueReceived);
}<input id="inputField" style="height:50px;width:300px;font-size:20pt;" type="text" value="">
From native layer, create a class and replicate the following.
class JSBridge(){
@JavascriptInterface
fun showMessageInNative(message:String){ //Received message from webview in native, process data }
}
While configuring web view, we need to set JavaScript interface as above JSBridge class.
mWebViewComponent.settings.javaScriptEnabled = true
mWebViewComponent.addJavascriptInterface(JSBridge(),"JSBridge")
Considering security:
If we are loading webpages which are known to our ecosystem, this wont have any issues wrt security. If this is not , opening interface and allowing WebView to communicate with native can be dangerous.🧐
As per Android API documentation:
When the HTML in the WebView is untrustworthy (for example, part or all of the HTML is provided by an unknown person or process), then an attacker can include HTML that executes your client-side code and possibly any code of the attacker’s choosing. As such, you should not use addJavascriptInterface() unless you wrote all of the HTML and JavaScript that appears in your WebView. You should also not allow the user to navigate to other web pages that are not your own, within your WebView. Instead, allow the user’s default browser application to open foreign links.
2.1 To send data from native layer to Webview.
Create a function in JavaScript to receive data in Html. Which will update inputField with the value received.
function updateFromNative(message){
document.getElementById("inputField").value = message;
}<input id="inputField" style="height:50px;width:300px;font-size:20pt;" type="text" value="">
Now from native layer, we can access this function by the following.😊👏 🎉
private fun sendDataToWebView(){
mWebViewComponent.evaluateJavascript(
"javascript: " +"updateFromNative(\"" + mEditText.text +
"\")",null)
}
And that's it, both the platforms are covered 😊👏 🎉
Now as you got the clear picture of Native and WebView communication, do have a trial and checkout how the same works in both platforms! 😇
Full source code of Android sample can be found in Github over here
Complete source of iOS sample can be found in Github over here
Do clap if you find this article helpful👏👏
Thanks for reading. Happy Coding! 🥳 Cheers! 🤜 🤛 🥂