Bind Webview to native app functions

Binding Webview clicks to native code

The webview might want to access some native features. Like opening a deeplink, showing the share drawer, etc.

  • callback native method should be binded with any webview.

  • The webview will pass eventJSON to the callback function.

The webview will call this function in the following ways -

app.callback(eventJSON); //Android
webkit.messageHandlers.callback.postMessage(eventJSON); // iOS

Download Sample Kotlin App from our Github

Download Sample React Native App from our Github

Android(Java)
iOS(Swift)
Android(Kotlin)
React Native
Android(Java)
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.util.Log;
import org.json.JSONObject;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = (WebView)findViewById(R.id.web_view);
webView.loadUrl("https://app-markk.customerglu.com/program"); // webview url
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewJavaScriptInterface(this), "app"); // **IMPORTANT** call it app
}
/*
* JavaScript Interface. Web code can access methods in here
* (as long as they have the @JavascriptInterface annotation)
*/
public class WebViewJavaScriptInterface{
private Context context;
/*
* Need a reference to the context in order to sent a post message
*/
public WebViewJavaScriptInterface(Context context){
this.context = context;
}
/*
* This method can be called from Android. @JavascriptInterface
* required after SDK version 17.
*/
@JavascriptInterface
// **IMPORTANT** call it callback
public void callback(String message){
JSONObject data = new JSONObject(message);
// data has the event information
Log.d(data);
}
}
}
iOS(Swift)
import UIKit
import WebKit
import Foundation
class ViewController: UIViewController , WKScriptMessageHandler{
@IBOutlet weak var mWebKitView: WKWebView!
@IBOutlet weak var mEdtTxt: UITextField!
var mNativeToWebHandler : String = "callback" // **IMPORTANT** call it callback
var webviewUrl: String = "https://app-markk.customerglu.com/program" // webview url
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string: webviewUrl)
let myRequest = URLRequest(url: myURL!)
mWebKitView.load(myRequest)
let contentController = WKUserContentController()
mWebKitView.configuration.userContentController = contentController
mWebKitView.configuration.userContentController.add(self, name: mNativeToWebHandler)
}
// message handler
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == mNativeToWebHandler {
// message.body holds JSON of the event
let jsonMessageString: String = message.body as? String;
let jsonDict = try JSONSerialization.jsonObject(with: jsonMessageString) as? NSDictionary
// // jsonDict has the event information
print(jsonDict)
}
}
}
Android(Kotlin)
package com.customerglu.kotlinwebviewnativecomm
import android.content.Context
import android.os.Bundle
import android.webkit.JavascriptInterface
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
// TODO: Replace url with the url for your program/campaign.
private val url = "<Provide-Your-campaign-url here>"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
exampleWebView.settings.javaScriptEnabled = true
exampleWebView.addJavascriptInterface(JSComm(this),"app")
exampleWebView.loadUrl(url)
}
/**
* Receive message from webview
*/
class JSComm(val context: Context){
@JavascriptInterface
fun callback(message:String){
// Capture message from webview and print as toast
Toast.makeText(context,message, Toast.LENGTH_LONG).show()
}
}
}
React Native
import React from "react";
import WebView, { WebViewMessageEvent } from "react-native-webview";
import { StyleSheet, Text, View } from "react-native";
export function GluWebView({ url }: { url: string }) {
/* Callback for the WebView */
function onWebViewEvent(event: WebViewMessageEvent) {
const data: IWebViewEvent = JSON.parse(event.nativeEvent.data);
console.log(data);
}
return (
<View style={styles.container}>
<WebView
source={{ uri: url }}
onMessage={onWebViewEvent} /* Pass the callback (line: 34) defined as props */
renderLoading={() => (
<Text style={styles.text}>Loading Webview...</Text>
)}
renderError={() => (
<Text style={styles.text}>Error Loading Webview...</Text>
)}
startInLoadingState
style={{ marginTop: 20 }}
/>
</View>
);
}
type IWebViewEvent = IOpenDeepLinkEvent | ICloseEvent | IShareEvent;
interface IOpenDeepLinkEvent {
eventName: "OPEN_DEEPLINK";
data: {
deepLink: string;
name: string;
};
}
interface ICloseEvent {
eventName: "CLOSE";
}
interface IShareEvent {
eventName: "SHARE";
data: {
channelName: "WHATSAPP" | "SMS" | "EMAIL" | "OTHERS";
text: string;
image: string;
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "stretch",
justifyContent: "center",
},
text: {
fontSize: 30,
},
});

EventJSON

  • The native callback function should be able to identify the event using eventName property present in the JSON.

  • The data property contains data relevant to that eventName.

Types of events possible -

Example use case: Webview wants to redirect user to cart page on a button click.

Event Structure -

{
eventName: "OPEN_DEEPLINK",
data: {
name: "shop",
deepLink: "whatsapp://send"
}
}

2. CLOSE WEBVIEW

Example use case: User wants to close the webview by clicking on close button.

Event Structure -

{
eventName: "CLOSE",
data: null
}

3. SHARE

Example use case: User might want to use social share for referral or sharing reward the user won.

Event Structure:

{
eventName: "SHARE"
data: {
channelName: "WHATSAPP", // OR SMS, EMAIL, OTHERS,
text: “Hi, I just won Rs 500, checkout...,
image: "https://img.glu.com/asdajefneju.png"
}
}