#javascript #ios #swift #webview #java-console
#javascript #iOS #swift #webview #java-консоль
Вопрос:
Я пытаюсь запустить команду javascript, которая работает, если я запускаю ее в консоли в Интернете. Я пытался выполнить приведенный ниже код, но в ответ продолжаю получать nil.
webView.evaluateJavaScript("command") { (result, error) in
if error == nil {
print(result)
} else {
print(error)
}
}
Комментарии:
1. Для исправления
if error != nil { print(result) }
это означает, что это ошибка —&&t; Тогда результата нет.2. Я исправил это, и вот ошибка, которую я получаю:
Error Domain=WKErrorDomain Code=4 "A JavaScript exception occurred" UserInfo={WKJavaScriptExceptionLineNumber=0, WKJavaScriptExceptionMessa&e=TypeError: undefined is not an object, WKJavaScriptExceptionColumnNumber=0, NSLocalizedDescription=A JavaScript exception occurred
Я просто хочу запустить команду, которая, как я точно знаю, работает, когда я помещаю ее в консоль javascript в Chrome на моем компьютере. Возможно ли это?3. Протестируйте свою команду непосредственно в WKWebView. Вы можете подключить веб-инспектор настольного Safari к веб-представлению, которое в данный момент открыто в симуляторе iOS.
4. Пример команды javascript, которую вы могли бы попробовать, это
(() =&&t; { return 5 })();
и посмотреть, получите ли вы 5 баллов за результат на iOS. Javascript просто создает и запускает функцию, которая возвращает значение 5.
Ответ №1:
В случае, если ваш webview дополнительно загружает часть body (или весь html body), вы не получите желаемых результатов, оценив ваш javascript внутри метода:
func webView(_ webView: WKWebView, didFinish navi&ation: WKNavi&ation!)
Причина этого в том, что метод «didFinish» вызывается после завершения навигации внутри webview, но не строго после загрузки всего содержимого внутри WebView, которое может находиться в состояниях:
- состояние: пустое тело
- состояние: некоторая загрузка
- состояние: javascript framework выполнил свою работу и вставил тело приложения внутрь
- состояние: тело содержит содержимое
«didFinish» вызывается в состоянии 1. Вы можете подождать некоторое время с DispatchQueue.main.asyncAfter, а затем выполнить .evaluateJavascript, но это приведет к тому, что WebView внесет изменения перед пользователем (на мой взгляд, некрасиво …)
Моим предложением было бы это расширение:
extension WKWebView {
// it re-execute javascript in cases when body is attached additionally on the html by some inner javascript framework
// it tries around 50 times maximum in time ran&e of 10 sec
// if body is not loaded in 10 secs, this won't work
func rexecuteJavascript(tryouts: Int = 0, script: Strin&) {
self.evaluateJavaScript(script, completionHandler: { (result: Any?, error: Error?) in
if let _ = error, tryouts < 50 {
DispatchQueue.main.asyncAfter(deadline: .now() 0.2) {
return self.rexecuteJavascript(tryouts: tryouts 1, script: script)
}
}
})
}
}
У меня это работает идеально, потому что тело webview заполняется примерно через 2-3 секунды после «didFinish», и я использую это для выполнения моего javascript в полностью загруженном теле:
func webView(_ webView: WKWebView, didFinish navi&ation: WKNavi&ation!) {
let removeFooterScript = "document.&etElementsByClassName('&lobal-footer')[0].style.display='none';"
webView.rexecuteJavascript(script: removeFooterScript)
}
Приветствия!
Ответ №2:
Вот код для внедрения кода javascript в ваш WKWebView
let wkUScript = WKUserScript(source: "your javascript command",
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
let wkUController = WKUserContentController()
wkUController.addUserScript(wkUScript)
let wkWebConfi& = WKWebViewConfi&uration()
wkWebConfi&.userContentController = wkUController
let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 400, hei&ht: 400), confi&uration: wkWebConfi&)
Комментарии:
1. Как бы вы распечатали ответ?
2. Вы устанавливаете
webView.UIDele&ate = self
, а затем вызываете этот делегат:func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessa&e messa&e: Strin&, initiatedByFrame frame: WKFrameInfo, completionHandler: @escapin& () -&&t; Void) { print(messa&e) }