Event handling
Our widgets will publish events to the following interfaces if they are available:
window.Android.postMessage
window.webkit.messageHandlers.ios.postMessage
window.ReactNativeWebView.postMessage
Events are sent as a JSON string with the following format:
{
name,
type,
metadata
}
We also dispatch these events to the top-level window with window.dispatchEvent
(payload in event.details)
Example Android code to set up the window.Android.postMessage and handle the event in Kotlin:
// WebAppInterface.kt
import android.webkit.JavascriptInterface
class WebAppInterface(private val fragment: DashboardFragment) {
@JavascriptInterface
public fun postMessage(message: String) {
// Handle the received message
fragment.activity?.runOnUiThread {
fragment.handleMessageFromWebView(message)
}
}
}
// Your view fragment
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.fragment.app.Fragment
import com.example.basicnav.databinding.FragmentDashboardBinding
import org.json.JSONObject
const val WIDGET_URI = "https://widget-domain-that-we-provide"
class DashboardFragment : Fragment() {
private var _binding: FragmentDashboardBinding? = null
private val binding get() = _binding!!
private lateinit var webView: WebView
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDashboardBinding.inflate(inflater, container, false)
val root: View = binding.root
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true)
}
webView = binding.webView
webView.webViewClient = WebViewClient()
webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true
webView.addJavascriptInterface(WebAppInterface(this), "Android")
return root
}
fun handleMessageFromWebView(message: String) {
Log.d("DashboardFragment", "Received message from WebView: $message")
try {
val jsonObject = JSONObject(message)
when (val type = jsonObject.getString("type")) {
"externalLink" -> {
val url = jsonObject.getString("url")
openExternalLink(url)
}
else -> {
Log.d("DashboardFragment", "Received message $type")
}
}
} catch (e: Exception) {
Log.e("DashboardFragment", "Error parsing JSON message", e)
}
}
private fun openExternalLink(url: String) {
try {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
} catch (e: Exception) {
Log.e("DashboardFragment", "Error opening external link", e)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Retrieve the fragment from the arguments
val fragment = arguments?.getString("fragment")
val widgetId = "your-widget-id"
val token = "token-for-user"
Log.d("DashboardFragment", "URL fragment received: $fragment")
// Load the WebView with the received parameters
val url = "$WIDGET_URI?widget_id=$widgetId&token=$token#$fragment"
webView.loadUrl(url)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Example iOS Code:
import SwiftUI
import WebKit
import Foundation
struct Payload: Codable {
let type: String
let url: String
}
struct WebView: UIViewRepresentable {
var url: URL
var javascript: String
var messageHandler: WKScriptMessageHandler
func makeUIView(context: Context) -> WKWebView {
let preferences = WKPreferences()
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
configuration.userContentController.add(messageHandler, name: "ios")
let webView = WKWebView(frame: .zero, configuration: configuration)
webView.navigationDelegate = context.coordinator
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.load(URLRequest(url: url))
}
}
class MessageHandler: NSObject, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "ios", let jsonString = message.body as? String {
print("Received message from JS: \(jsonString)")
guard let jsonData = jsonString.data(using: .utf8) else {
fatalError("Failed to convert string to data")
}
do {
let decoder = JSONDecoder()
let payload = try decoder.decode(Payload.self, from: jsonData)
if payload.type == "externalLink", let url = URL(string: payload.url) {
print("OPEN URL: \(payload.url)")
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
print("Cannot open URL")
}
}
} catch {
print("Error decoding JSON:", error)
}
}
}
}
struct ContentView: View {
var body: some View {
let fragment = "your-fragment-string" // Retrieved from universal link
let widgetId = "your-widget-id" // supplied to you
let token = "token-for-user" // retrieved from your backend
let baseUri = "https://widget-domain"
// Construct URL
let urlString = "\(baseUri)?widget_id=\(widgetId)&token=\(token)#\(fragment)"
let url = URL(string: urlString)!
return WebView(url: url)
}
}
Updated 2 days ago
What’s Next