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 -
1
app.callback(eventJSON); //Android
2
webkit.messageHandlers.callback.postMessage(eventJSON); // iOS
3
Copied!

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
1
2
import android.os.Bundle;
3
import android.support.v7.app.AppCompatActivity;
4
import android.support.v7.widget.Toolbar;
5
import android.view.Menu;
6
import android.view.MenuItem;
7
import android.webkit.WebSettings;
8
import android.webkit.WebView;
9
import android.util.Log;
10
import org.json.JSONObject;
11
12
public class MainActivity extends Activity {
13
@Override
14
protected void onCreate(Bundle savedInstanceState) {
15
super.onCreate(savedInstanceState);
16
setContentView(R.layout.activity_main);
17
WebView webView = (WebView)findViewById(R.id.web_view);
18
webView.loadUrl("https://app-markk.customerglu.com/program"); // webview url
19
webView.getSettings().setJavaScriptEnabled(true);
20
webView.addJavascriptInterface(new WebViewJavaScriptInterface(this), "app"); // **IMPORTANT** call it app
21
}
22
/*
23
* JavaScript Interface. Web code can access methods in here
24
* (as long as they have the @JavascriptInterface annotation)
25
*/
26
public class WebViewJavaScriptInterface{
27
private Context context;
28
/*
29
* Need a reference to the context in order to sent a post message
30
*/
31
public WebViewJavaScriptInterface(Context context){
32
this.context = context;
33
}
34
/*
35
* This method can be called from Android. @JavascriptInterface
36
* required after SDK version 17.
37
*/
38
@JavascriptInterface
39
// **IMPORTANT** call it callback
40
public void callback(String message){
41
JSONObject data = new JSONObject(message);
42
// data has the event information
43
Log.d(data);
44
}
45
}
46
}
47
Copied!
1
import UIKit
2
import WebKit
3
import Foundation
4
5
class ViewController: UIViewController , WKScriptMessageHandler{
6
@IBOutlet weak var mWebKitView: WKWebView!
7
@IBOutlet weak var mEdtTxt: UITextField!
8
var mNativeToWebHandler : String = "callback" // **IMPORTANT** call it callback
9
var webviewUrl: String = "https://app-markk.customerglu.com/program" // webview url
10
override func viewDidLoad() {
11
super.viewDidLoad()
12
let myURL = URL(string: webviewUrl)
13
let myRequest = URLRequest(url: myURL!)
14
mWebKitView.load(myRequest)
15
let contentController = WKUserContentController()
16
mWebKitView.configuration.userContentController = contentController
17
mWebKitView.configuration.userContentController.add(self, name: mNativeToWebHandler)
18
}
19
20
// message handler
21
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
22
if message.name == mNativeToWebHandler {
23
// message.body holds JSON of the event
24
let jsonMessageString: String = message.body as? String;
25
let jsonDict = try JSONSerialization.jsonObject(with: jsonMessageString) as? NSDictionary
26
// // jsonDict has the event information
27
print(jsonDict)
28
}
29
}
30
}
Copied!
1
package com.customerglu.kotlinwebviewnativecomm
2
3
import android.content.Context
4
import android.os.Bundle
5
import android.webkit.JavascriptInterface
6
import android.widget.Button
7
import android.widget.Toast
8
import androidx.appcompat.app.AppCompatActivity
9
import kotlinx.android.synthetic.main.activity_main.*
10
11
class MainActivity : AppCompatActivity() {
12
13
// TODO: Replace url with the url for your program/campaign.
14
private val url = "<Provide-Your-campaign-url here>"
15
16
override fun onCreate(savedInstanceState: Bundle?) {
17
super.onCreate(savedInstanceState)
18
setContentView(R.layout.activity_main)
19
exampleWebView.settings.javaScriptEnabled = true
20
exampleWebView.addJavascriptInterface(JSComm(this),"app")
21
exampleWebView.loadUrl(url)
22
23
}
24
25
/**
26
* Receive message from webview
27
*/
28
class JSComm(val context: Context){
29
@JavascriptInterface
30
fun callback(message:String){
31
// Capture message from webview and print as toast
32
Toast.makeText(context,message, Toast.LENGTH_LONG).show()
33
}
34
}
35
36
}
Copied!
1
import React from "react";
2
import WebView, { WebViewMessageEvent } from "react-native-webview";
3
import { StyleSheet, Text, View } from "react-native";
4
5
export function GluWebView({ url }: { url: string }) {
6
7
/* Callback for the WebView */
8
function onWebViewEvent(event: WebViewMessageEvent) {
9
const data: IWebViewEvent = JSON.parse(event.nativeEvent.data);
10
console.log(data);
11
}
12
13
return (
14
<View style={styles.container}>
15
<WebView
16
source={{ uri: url }}
17
onMessage={onWebViewEvent} /* Pass the callback (line: 34) defined as props */
18
renderLoading={() => (
19
<Text style={styles.text}>Loading Webview...</Text>
20
)}
21
renderError={() => (
22
<Text style={styles.text}>Error Loading Webview...</Text>
23
)}
24
startInLoadingState
25
style={{ marginTop: 20 }}
26
/>
27
</View>
28
);
29
}
30
31
type IWebViewEvent = IOpenDeepLinkEvent | ICloseEvent | IShareEvent;
32
33
interface IOpenDeepLinkEvent {
34
eventName: "OPEN_DEEPLINK";
35
data: {
36
deepLink: string;
37
name: string;
38
};
39
}
40
41
interface ICloseEvent {
42
eventName: "CLOSE";
43
}
44
45
interface IShareEvent {
46
eventName: "SHARE";
47
data: {
48
channelName: "WHATSAPP" | "SMS" | "EMAIL" | "OTHERS";
49
text: string;
50
image: string;
51
};
52
}
53
54
55
const styles = StyleSheet.create({
56
container: {
57
flex: 1,
58
backgroundColor: "#fff",
59
alignItems: "stretch",
60
justifyContent: "center",
61
},
62
text: {
63
fontSize: 30,
64
},
65
});
66
Copied!
1
import 'package:flutter/material.dart';
2
import 'package:webview_flutter/webview_flutter.dart';
3
4
class MyWebView extends StatefulWidget {
5
@override
6
WebState createState() => WebState();
7
}
8
9
class WebState extends State<MyWebView> {
10
@override
11
Widget build(BuildContext context) {
12
return Scaffold(
13
body: SafeArea(
14
top: true,
15
child: WebView(
16
initialUrl: "CAMPAIGN_URL", //Need to put Campaign url
17
javascriptMode: JavascriptMode.unrestricted, //IMPORTANT for enablig javascript
18
javascriptChannels: <JavascriptChannel>[
19
JavascriptChannel(
20
name: 'app', // Name is "app"
21
onMessageReceived: (s) {
22
print(s.message); // s.message contains event data like {"eventName":"CLOSE","data":null}
23
}),
24
].toSet(),
25
),
26
));
27
}
28
}
Copied!

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 -
1
{
2
eventName: "OPEN_DEEPLINK",
3
data: {
4
name: "shop",
5
deepLink: "whatsapp://send"
6
}
7
}
Copied!

2. CLOSE WEBVIEW

Example use case: User wants to close the webview by clicking on close button.
Event Structure -
1
{
2
eventName: "CLOSE",
3
data: null
4
}
Copied!

3. SHARE

Example use case: User might want to use social share for referral or sharing reward the user won.
Event Structure:
1
{
2
eventName: "SHARE"
3
data: {
4
channelName: "WHATSAPP", // OR SMS, EMAIL, OTHERS,
5
text: “Hi, I just won Rs 500, checkout...,
6
image: "https://img.glu.com/asdajefneju.png"
7
}
8
}
Copied!