我是 SwiftUI 的新手,我在 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 的响应
我在 swift 中找到了此代码,但不明白如何在 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 中配置相同的配置吗?如果是的话,那么如何配置?
您实施的内容是正确的,但是您错过了
WKWebViewConfiguration
对象。
您需要创建 Web 视图配置来注册消息处理程序以供您的 javascript 代码调用,请参见下文:
创建一个可以从 JavaScript 代码接收回调的类:
let scriptMessageHandler = ScriptMessageHandler()
class ScriptMessageHandler: NSObject, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
}
}
创建一个配置对象并传递
ScriptMessageHandler
的对象作为处理程序。
let config = WKWebViewConfiguration()
config.userContentController = WKUserContentController()
config.userContentController.add(scriptMessageHandler, name: "backHomePage")```
您可以在创建 Web 视图对象并将此配置传递到您的 Web 视图之前,在
makeUIView(context:) -> WKWebView
方法实现中执行此操作。
在Javascript中,可以像下面这样调用上面的配置:
function onClick() {
window.webkit.messageHandlers.backHomePage.postMessage("success");
}
当从 JavaScript 调用上述函数时,您将在
userContentController(_ didReceive:)
实现中收到回调。
基于@KishanSadhwani的回答,下面是一个通过测试的示例:
import SwiftUI
import WebKit
let testHTML = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello Alert</title>
</head>
<body>
<button onclick="showAlert()">Click me to send message to native app</button>
<script>
function showAlert() {
window.webkit.messageHandlers.NAME.postMessage("[MESSAGE TO APP]");
}
</script>
</body>
</html>
"""
class LogBookScriptMessageHandler: NSObject, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
}
}
struct LogBookWebView: UIViewRepresentable {
typealias UIViewType = WKWebView
func makeUIView(context: Context) -> WKWebView {
let config = WKWebViewConfiguration()
let handler = LogBookScriptMessageHandler()
config.userContentController.add(handler, name: "NAME")
let webView = WKWebView(frame: .zero, configuration: config)
webView.loadHTMLString(testHTML, baseURL: nil)
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
}
}
#Preview {
LogBookWebView()
}
希望这有帮助。
我自己检查了这个,它对我来说工作正常。
struct WebView: UIViewRepresentable {
func makeUIView(context: Context) -> WKWebView {
let coordinator = makeCoordinator()
let userContentController = WKUserContentController()
userContentController.add(coordinator, name: "bridge")
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let wkwebview = WKWebView(frame: .zero, configuration: configuration)
wkwebview.navigationDelegate = coordinator
return wkwebview
}
func updateUIView(_ uiView: WKWebView, context: Context) {
let content = """
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1, viewport-fit=cover">
</head>
<body>
<button>click me</button>
<hr/>
<div id="log"></div>
<script>
const log = (msg) => {
const p = document.createElement('p')
p.textContent = msg
document.querySelector('#log').append(p)
}
// to receive messages from native
webkit.messageHandlers.bridge.onMessage = (msg) => {
log('from native:' + msg)
}
document.querySelector('button').addEventListener('click', () => {
log(typeof webkit.messageHandlers.bridge.postMessage)
// send messages to native
webkit.messageHandlers.bridge.postMessage('{"msg": "hello?","id": ' + Date.now() + '}')
})
</script>
</body>
</html>
"""
uiView.loadHTMLString(content, baseURL: nil)
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
private var webView: WKWebView?
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.webView = webView
print("WebView: navigation finished")
}
func webViewDidFinishLoad(webView: WKWebView) {
print("Loaded: \(String(describing: webView.url))")
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("Loaded: \(String(describing: webView.url))")
}
// this method is used to get the message from the Webview
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("Signal: \(message.body)")
messageToWebview(msg: "iOS Native")
}
// this method is used to send the message to the Webview
func messageToWebview(msg: String) {
self.webView?.evaluateJavaScript("webkit.messageHandlers.bridge.onMessage('\(msg)')")
}
}
}
希望这对您有帮助