оценитьJavaScript в swiftui
Как заставить работать evalJavaScript, когда сообщение получено из веб-просмотра?
print (message.body) <--- это работает
parent?.evaluateJavaScript("document.getElementsByClassName('mat-toolbar-single-row')[0].style.backgroundColor = 'red'", завершения Handler: nil) <--- это не
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)
}
}
}
2 ответа
Решение
Вот возможный подход. Поскольку у меня нет предполагаемой среды тестирования, я не смог полностью протестировать ее, но вся инфраструктура построена правильно. Так что вы можете попробовать
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")
}
}
}