Joining the two worlds (Web and Native mobile apps)
Last year I was working on an application for a fintech startup and we were exploring some ideas as how we can communicate between the payment gateway that they have already created in their web application and native mobile applications. We were looking for something more reliable and secure instead of traditional way of listening to URL change. As you already know that interacting between webview and native application is very difficult because it is like dealing with two different worlds but we found a solution. The solution that we came across was the javascript callback and cool things is that both the mobile application platforms Android and iOS supports them. You can use this technology for many other use cases for which you need interactions between javascript and native mobile applications.
Here I will discuss some points which will help you to implement callback functionality between javascript and both the popular mobile platform(Android and iOS), along with some of the use cases for which you can leverage this technology.
Javascript to Android
Let's start by adding steps for the callback from javascript to android.
First, you have to create a class and make a function with @JavascriptInterface that will be called from javascript as follows:
public class MyClient{
/** Instantiate the receiver and set the context */
Context mContext; MyClient(Context c) {
mContext = c;
}
@JavascriptInterface
public void showMessage(String message){
Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show()
}
}
Add the following lines to initialise your webview:
WebView webView;
webView = (WebView) findViewById(R.id.webView); webView.setWebChromeClient(new WebChromeClient());
webView.getSettings().setJavaScriptEnabled(true);webView.addJavascriptInterface(new MyClient(this), "MyClient") // Pass receiver class object and the name which can be called from JS
Finally, you can call the function declared in the class as follows from Javascript:
MyClient.showMessage('fruit');
Android to Javascript
Now let's do the fun part of doing the reverse communication
To call the Javascript function without listening to return value you can simply call the function like this:
webview.loadUrl("javascript:myFunction();");
In order to get the javascript function’s return value, you need to use evaluateJavascript like this:
webView.evaluateJavascript("javascript:myFunction();",
new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
// Do what you want with the return value
}
});
iOS to Javascript
After iOS 8.0 WKWebView is the new Webview class that is recommended by iOS to enable the support for JS callback you just have to add the following configuration in WKWebView
let contentController = WKUserContentController()
contentController.add(self, name: "MyClient") //JS callback namelet webConfiguration = WKWebViewConfiguration()
webConfiguration.userContentController = contentControllerwebView = WKWebView(frame: .zero, configuration: webConfiguration)
From JS you can call this by writing the following code:
var message = {'fruit','apple'}; window.webkit.messageHandlers.MyClient.postMessage(message);
You will get the event for this as follows in your controller:
import WebKitclass WebViewController: UiViewController,WKScriptMessageHandler{func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "MyClient"{
debugPrint("Callback body: \(message.body)")
}
}
}
Javascript to iOS
The WKUserScript object, when added to the userContentController, allows developers to take JavaScript and inject it into a webpage. Here’s a simple example of adding a script to change the background color of the web page:
let contentController = WKUserContentController()let scriptSource = "document.body.style.backgroundColor = `red`;"
let script = WKUserScript(source: scriptSource,
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
contentController.addUserScript(script) let config = WKWebViewConfiguration()
config.userContentController = contentController let webView = WKWebView(frame: .zero, configuration: config)
UseCases
- User registration from a webview and receive the token and login status on the native counterpart
- Payment gateway integration using webview and getting the status of the payment
- To share some business logic between all the platforms(web, android, iOS) like date-time manipulations or generating certain encryption keys for authentication purposes.
Summary
Using callbacks to pass information between Webview and their native counterparts is a more secure and reliable way. So whenever you are considering to write a Webview app or part of your app runs on Webview you should consider using these callbacks to pass the information or handle interactions between two different worlds.