Binding Webview to Native App Functions

Handling the interaction between webview programs and the app

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

Download Sample Flutter App from our Github

Android(Java)
iOS(Swift)
Android(Kotlin)
React Native
Flutter
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);
}
}
}
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)
}
}
}
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()
}
}
}
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,
},
});
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class MyWebView extends StatefulWidget {
@override
WebState createState() => WebState();
}
class WebState extends State<MyWebView> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
top: true,
child: WebView(
initialUrl: "CAMPAIGN_URL", //Need to put Campaign url
javascriptMode: JavascriptMode.unrestricted, //IMPORTANT for enablig javascript
javascriptChannels: <JavascriptChannel>[
JavascriptChannel(
name: 'app', // Name is "app"
onMessageReceived: (s) {
print(s.message); // s.message contains event data like {"eventName":"CLOSE","data":null}
}),
].toSet(),
),
));
}
}

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.
Check out all possible Webview events here.