如何在SwiftUI中监听JavaScript回调?
在SwiftUI中实现WebView与JavaScript的消息交互
我是SwiftUI新手,已按如下方式创建了WebView:
struct WebView: UIViewRepresentable { @Binding var title: String var url: URL var loadStatusChanged: ((Bool, Error?) -> Void)? = nil func makeCoordinator() -> WebView.Coordinator { Coordinator(self) } func makeUIView(context: Context) -> WKWebView { let view = WKWebView() view.navigationDelegate = context.coordinator view.load(URLRequest(url: url)) return view } func updateUIView(_ uiView: WKWebView, context: Context) { // you can access environment via context.environment here // Note that this method will be called A LOT } func onLoadStatusChanged(perform: ((Bool, Error?) -> Void)?) -> some View { var copy = self copy.loadStatusChanged = perform return copy } class Coordinator: NSObject, WKNavigationDelegate,WKScriptMessageHandler { @State private var studentAppID = UserDefaults.standard.string(forKey: "studentAppID") let parent: WebView init(_ parent: WebView) { self.parent = parent } func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { print(webView.url as Any) parent.loadStatusChanged?(true, nil) } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { print(webView as Any) print(webView.url as Any) parent.title = webView.title ?? "" webView.evaluateJavaScript("document.getElementsByName('applnID')[0].value='\(studentAppID!)'", completionHandler: nil) parent.loadStatusChanged?(false, nil) } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { parent.loadStatusChanged?(false, error) } func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { // guard let dict = message.body as? [String : AnyObject] else { // return // } print(message.body) } } }
我想配置相关功能,以便在用户点击WebView中的按钮标签时接收来自WebView的响应。我找到了UIKit中的实现代码,但不清楚如何在SwiftUI中使用,代码如下:
class ViewController: UIViewController, WKScriptMessageHandler { let content = """ <!DOCTYPE html><html><body> <button onclick="onClick()">Click me</button> <script> function onClick() { window.webkit.messageHandlers.backHomePage.postMessage("success"); } </script> </body></html> """ 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) } }
请问是否可以在SwiftUI中实现相同配置?如果可以,具体该怎么做?
可以实现,具体修改步骤如下:
1. 修改makeUIView方法,添加WKWebView配置
在创建WKWebView时,先初始化WKWebViewConfiguration,并将Coordinator注册为指定名称的消息处理器:
func makeUIView(context: Context) -> WKWebView { let config = WKWebViewConfiguration() // 注册消息处理器,名称要和JavaScript中调用的一致 config.userContentController.add(context.coordinator, name: "backHomePage") let view = WKWebView(frame: .zero, configuration: config) view.navigationDelegate = context.coordinator view.load(URLRequest(url: url)) return view }
2. 完善Coordinator中的消息处理逻辑
给WebView添加消息回调属性,并在Coordinator中把收到的JS消息传递给SwiftUI视图:
struct WebView: UIViewRepresentable { @Binding var title: String var url: URL var loadStatusChanged: ((Bool, Error?) -> Void)? = nil // 添加JS消息回调属性 var jsMessageReceived: ((Any) -> Void)? = nil // ... 原有代码不变 // 添加链式调用方法,用于绑定回调 func onJsMessageReceived(perform: ((Any) -> Void)?) -> some View { var copy = self copy.jsMessageReceived = perform return copy } class Coordinator: NSObject, WKNavigationDelegate,WKScriptMessageHandler { // ... 原有代码不变 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { // 根据消息名称区分处理(多消息场景下可用) if message.name == "backHomePage" { // 将消息传递给SwiftUI视图的回调 parent.jsMessageReceived?(message.body) } } } }
3. 在SwiftUI视图中使用WebView并绑定回调
struct ContentView: View { @State private var webViewTitle = "" var body: some View { WebView(title: $webViewTitle, url: URL(string: "your-web-url")!) .onJsMessageReceived { message in // 处理收到的JavaScript消息 print("SwiftUI收到消息:\(message)") // 可在此执行页面跳转、状态更新等操作 } } }
原理说明
通过WKWebViewConfiguration的userContentController注册消息处理器后,当WebView中的JavaScript调用window.webkit.messageHandlers.backHomePage.postMessage("内容")时,Coordinator的userContentController(_:didReceive:)方法会被触发,此时可以将消息传递给SwiftUI视图进行后续处理。
内容的提问来源于stack exchange,提问作者Muju
相关产品推荐
相关产品推荐

