Reputation: 33
I want javascript to send a message back to my WKWebView object, but I get nothing in response. I know the script is running, as the color changes, but I am expecting to also see "trigger from JS" printed in the console, which I don't. If I run the html in Chrome, the javascript console says "Cannot read property 'messageHandlers' of undefined". If I build for iOS (using UIViewRepresentable, MakeUIView and UpdateUIView) the result is the same. If anyone can spot what I have missed I would greatly appreciate it.
This is the entirety of the code:
import SwiftUI
import WebKit
class HtmlData {
let html = """
<!DOCTYPE html>
<html>
<body>
<button onclick="sendMessage()">Send Message</button>
<script>
function sendMessage() {
document.body.style.backgroundColor = "red";
window.webkit.messageHandlers.testMessage.postMessage("trigger from JS");
}
</script>
</body>
</html>
"""
}
struct ContentView: View {
let htmlData = HtmlData()
var body: some View {
JSWebView(html: htmlData.html)
}
}
struct JSWebView: NSViewRepresentable {
let html: String
func makeNSView(context: Context) -> WKWebView {
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
return WKWebView()
}
func updateNSView(_ view: WKWebView, context: Context) {
let userContentController = WKUserContentController()
let handler = ContentController(view)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
configuration.userContentController.add(handler, name: "testMessage")
view.loadHTMLString(html, baseURL: Bundle.main.bundleURL)
}
class ContentController: NSObject, WKScriptMessageHandler {
var parent: WKWebView?
init(_ parent: WKWebView?) {
self.parent = parent
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
}
}
}
Upvotes: 3
Views: 2613
Reputation: 891
Configuration must be passed into the constructor of WKWebView. It can't be set after initialization.
struct JSWebView: NSViewRepresentable {
let html: String
func makeNSView(context: Context) -> WKWebView {
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
let handler = MessageHandler()
let configuration = WKWebViewConfiguration()
configuration.userContentController.add(handler, name: "testMessage")
return WKWebView(frame: .zero, configuration: configuration)
}
func updateNSView(_ view: WKWebView, context: Context) {
view.loadHTMLString(html, baseURL: Bundle.main.bundleURL)
}
class MessageHandler: NSObject, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
}
}
}
Upvotes: 3