I have a webview where I’m setting up a bridge between javascript and the underlying native code.
I am able to call a swift function from javascript, but I am not able to call javascript functions from swift with evaluateJavaScript
.
The weird part is I am able to change the DOM with evaluateJavaScript
, for instance does this work:
self.webView?.evaluateJavaScript("document.body.style.backgroundColor = 'orange'")
But when I call a function on window nothing happens. Except if I use a function on a object, I get an undefined exception, the object is undefined.
I’m suspecting this is something related to the window object?
I am using Xcode 15.4 and targeting iOS 17.5.
This is starting to get frustrating, and I’ve searched the big internet for answers but nothing works.
And yes I’m waiting for the page to be fully loaded, the page is secured and the function works from the developer console..
Here is my code implementation
import SwiftUI
import WebKit
protocol WebViewMessageDelegate: AnyObject {
func didReciveMessage(_ message: String)
}
struct WebView: UIViewRepresentable {
weak var delegate: WebViewMessageDelegate?
init(delegate: WebViewMessageDelegate?) {
self.delegate = delegate
}
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
weak var delegate: WebViewMessageDelegate?
var webView: WKWebView?
init(delegate: WebViewMessageDelegate?) {
self.delegate = delegate
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.webView = webView
print("Loaded");
self.messageToWebview(msg: "Hello")
}
// receive message from wkwebview
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
//print(message.body)
let date = Date()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// self.messageToWebview(msg: "hello, I got your messsage: (message.body) at (date)")
self.messageToWebview(msg: "HELLO")
}
delegate?.didReciveMessage("(message.body)")
}
func messageToWebview(msg: String) {
print("messageToWebview: (msg)")
// let script = "window.bridge.onMessage('(msg.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "")')"
let script = "window.test()"
// self.webView?.evaluateJavaScript("bridge.onMessage('GO hello')")
self.webView?.evaluateJavaScript(script) { (result, error) in
if let error = error {
print("Error evaluating JavaScript: (error)")
} else {
print("JavaScript evaluation result: (String(describing: result))")
}
}
//self.webView?.evaluateJavaScript("document.body.style.backgroundColor = 'orange'")
//self.webView?.evaluateJavaScript("webkit.messageHandlers.bridge.onMessage('(msg)')")
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(delegate: delegate)
}
func makeUIView(context: Context) -> WKWebView {
let coordinator = makeCoordinator()
let userContentController = WKUserContentController()
userContentController.add(coordinator, name: "bridge")
let prefs = WKWebpagePreferences()
prefs.allowsContentJavaScript = true
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
configuration.defaultWebpagePreferences = prefs
let _wkwebview = WKWebView(frame: .zero, configuration: configuration)
_wkwebview.navigationDelegate = coordinator
// Set transperrant background
_wkwebview.isOpaque = false
_wkwebview.backgroundColor = UIColor.clear
_wkwebview.scrollView.backgroundColor = UIColor.clear
return _wkwebview
}
func updateUIView(_ webView: WKWebView, context: Context) {
guard let url = URL(string: "https://playground.dev.hololink.io") else {
return
}
webView.load(URLRequest(url: url))
}
}
struct ContentView: View {
var delegate: WebViewMessageDelegate?
var body: some View {
VStack {
WebView(delegate: delegate)
}
}
}
Dennis Christensen is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.