Technologies:
Tolerim
a month ago
What is the procedure for receiving JavaScript Callbacks from SwiftUI?
As a new SwiftUI developer, I have created a WebView in my app. Here's the code:
struct WebView: UIViewRepresentable {
@Binding var title: String
var url: URL
var loadStatusChanged: ((Bool, Error?) -> Void)? = nil
// ...
}
I want to configure the function so that I can receive a response from the WebView when the user clicks on the button tag in the WebView. I found some code in Swift that achieves this, but I don't know how to use it in SwiftUI. Here's the code:
class ViewController: UIViewController, WKScriptMessageHandler {
let content = """
"""
override func viewDidLoad() {
super.viewDidLoad()
let config = WKWebViewConfiguration()
config.userContentController = WKUserContentController()
config.userContentController.add(self, name: "backHomePage")
let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 200, height: 200), configuration: config)
view.addSubview(webView)
webView.loadHTMLString(content, baseURL: nil)
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
}
}
Can I achieve the same thing in SwiftUI? If so, how?Answers(1)
Tolerim
a month ago
Verified Answer
Yes, you can configure the same functionality in SwiftUI using the UIViewRepresentable protocol to create a WebView and a class conforming to WKScriptMessageHandler protocol to handle the message received from the WebView when the button is clicked.
Here's an example of how you can configure the same functionality in your SwiftUI WebView:
First, update the Coordinator class of your WebView struct to conform to WKScriptMessageHandler protocol:
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
// ...
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
// handle the message received from the WebView here
}
}
Then, update your makeUIView function to add the script message handler and the script to execute when the button is clicked:
func makeUIView(context: Context) -> WKWebView {
let view = WKWebView()
let script = """
function onClick() {
window.webkit.messageHandlers.backHomePage.postMessage("success");
}
document.querySelector('button').addEventListener('click', onClick);
"""
let userContentController = WKUserContentController()
userContentController.add(context.coordinator, name: "backHomePage")
let userScript = WKUserScript(source: script, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
userContentController.addUserScript(userScript)
view.configuration.userContentController = userContentController
view.navigationDelegate = context.coordinator
view.load(URLRequest(url: url))
return view
}
Finally, implement the onLoadStatusChanged function to receive the callback when the button is clicked:
func onLoadStatusChanged(perform: ((Bool, Error?) -> Void)?) -> some View {
var copy = self
copy.loadStatusChanged = perform
if let message = copy.loadStatusChanged {
copy.loadStatusChanged = { isLoading, error in
message(isLoading, error)
if !isLoading {
let script = """
window.webkit.messageHandlers.backHomePage.postMessage("success")
"""
copy.uiView?.evaluateJavaScript(script)
}
}
}
return copy
}
With these changes, you should now be able to receive the message from the WebView when the button is clicked in your SwiftUI WebView.