在 swiftui 中评估 JavaScript
evaluateJavaScript in swiftui
如何在从 webview 收到消息时让 evaluateJavaScript 工作?
print(message.body) <--- this is working
parent?.evaluateJavaScript("document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor
= 'red'", completionHandler: nil) <--- this is not
struct WebView: UIViewRepresentable {
let request: URLRequest
let contentController = ContentController(nil)
func makeUIView(context: Context) -> WKWebView {
let webConfiguration = WKWebViewConfiguration()
let wkcontentController = WKUserContentController()
wkcontentController.add(contentController, name: "test")
webConfiguration.userContentController = wkcontentController
return WKWebView(frame: .zero, configuration: webConfiguration)
}
func updateUIView(_ view: WKWebView, context: Context) {
view.load(request)
}
class ContentController: NSObject, WKScriptMessageHandler {
var parent: WKWebView?
init(_ parent: WKWebView?) {
self.parent = parent
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "test"{
print(message.body)
parent?.evaluateJavaScript("document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'red'", completionHandler: nil)
}
}
}
这是可能的方法。由于我没有预期的测试环境,我无法完全测试它,但所有基础设施都构建正确。所以你可以试试
struct WebView: UIViewRepresentable {
let request: URLRequest
func makeUIView(context: Context) -> WKWebView {
let webConfiguration = WKWebViewConfiguration()
let wkcontentController = WKUserContentController()
wkcontentController.add(context.coordinator, name: "test")
webConfiguration.userContentController = wkcontentController
let webView = WKWebView(frame: .zero, configuration: webConfiguration)
context.coordinator.parent = webView // inject as weak
return webView
}
func updateUIView(_ view: WKWebView, context: Context) {
if view.url == nil {
view.load(request)
}
}
func makeCoordinator() -> ContentController {
ContentController() // let handler be a coordinator
}
class ContentController: NSObject, WKScriptMessageHandler {
weak var parent: WKWebView? // weak to avoid reference cycling
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
if message.name == "test" {
print(message.body)
parent?.evaluateJavaScript("document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'red'",
completionHandler: nil)
}
}
}
}
答案是将 WKWebview 传递给 ContentController() 而不是 nil
这是一个工作示例;
struct WebView: UIViewRepresentable {
let request: URLRequest
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ view: WKWebView, context: Context) {
let contentController = ContentController(view)
let userScript = WKUserScript(source: "document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'black'; alert('from iOS')", injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true)
view.configuration.userContentController.add(contentController, name: "test")
view.configuration.userContentController.addUserScript(userScript)
view.evaluateJavaScript("document.body.style.backgroundColor = '#4287f5';", completionHandler: nil)
view.load(request)
}
class ContentController: NSObject, WKScriptMessageHandler {
var parent: WKWebView?
init(_ parent: WKWebView?) {
self.parent = parent
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
parent?.evaluateJavaScript("document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'red';", completionHandler: nil)
print("from test")
}
}
}
如何在从 webview 收到消息时让 evaluateJavaScript 工作?
print(message.body) <--- this is working
parent?.evaluateJavaScript("document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'red'", completionHandler: nil) <--- this is not
struct WebView: UIViewRepresentable {
let request: URLRequest
let contentController = ContentController(nil)
func makeUIView(context: Context) -> WKWebView {
let webConfiguration = WKWebViewConfiguration()
let wkcontentController = WKUserContentController()
wkcontentController.add(contentController, name: "test")
webConfiguration.userContentController = wkcontentController
return WKWebView(frame: .zero, configuration: webConfiguration)
}
func updateUIView(_ view: WKWebView, context: Context) {
view.load(request)
}
class ContentController: NSObject, WKScriptMessageHandler {
var parent: WKWebView?
init(_ parent: WKWebView?) {
self.parent = parent
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "test"{
print(message.body)
parent?.evaluateJavaScript("document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'red'", completionHandler: nil)
}
}
}
这是可能的方法。由于我没有预期的测试环境,我无法完全测试它,但所有基础设施都构建正确。所以你可以试试
struct WebView: UIViewRepresentable {
let request: URLRequest
func makeUIView(context: Context) -> WKWebView {
let webConfiguration = WKWebViewConfiguration()
let wkcontentController = WKUserContentController()
wkcontentController.add(context.coordinator, name: "test")
webConfiguration.userContentController = wkcontentController
let webView = WKWebView(frame: .zero, configuration: webConfiguration)
context.coordinator.parent = webView // inject as weak
return webView
}
func updateUIView(_ view: WKWebView, context: Context) {
if view.url == nil {
view.load(request)
}
}
func makeCoordinator() -> ContentController {
ContentController() // let handler be a coordinator
}
class ContentController: NSObject, WKScriptMessageHandler {
weak var parent: WKWebView? // weak to avoid reference cycling
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
if message.name == "test" {
print(message.body)
parent?.evaluateJavaScript("document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'red'",
completionHandler: nil)
}
}
}
}
答案是将 WKWebview 传递给 ContentController() 而不是 nil
这是一个工作示例;
struct WebView: UIViewRepresentable {
let request: URLRequest
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ view: WKWebView, context: Context) {
let contentController = ContentController(view)
let userScript = WKUserScript(source: "document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'black'; alert('from iOS')", injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true)
view.configuration.userContentController.add(contentController, name: "test")
view.configuration.userContentController.addUserScript(userScript)
view.evaluateJavaScript("document.body.style.backgroundColor = '#4287f5';", completionHandler: nil)
view.load(request)
}
class ContentController: NSObject, WKScriptMessageHandler {
var parent: WKWebView?
init(_ parent: WKWebView?) {
self.parent = parent
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
parent?.evaluateJavaScript("document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'red';", completionHandler: nil)
print("from test")
}
}
}