Joining the two worlds (Web and Native mobile apps)

Bhavik Bansal
3 min readMay 24, 2019

--

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 name
let webConfiguration = WKWebViewConfiguration()
webConfiguration.userContentController = contentController
webView = 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

  1. User registration from a webview and receive the token and login status on the native counterpart
  2. Payment gateway integration using webview and getting the status of the payment
  3. 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.

--

--

Bhavik Bansal

Software Engineer at @gridle.io, a foodaholic and a huge sitcom fan. I may not be good at remembering things but i am really good at understanding them.