WKWebView evaluateJavaScript 不返回 html

Posted

技术标签:

【中文标题】WKWebView evaluateJavaScript 不返回 html【英文标题】:WKWebView evaluateJavaScript not returning html 【发布时间】:2017-04-02 16:34:28 【问题描述】:

我正在尝试使用 evaluatejavascript 解析从 WKWebView load() 返回的 html,但它从不打印任何内容。我这样做对吗?还有其他方法吗? didFinish 确实打印了。

import UIKit
import WebKit

class MyWebViewController: UIViewController, WKNavigationDelegate 

var webView: WKWebView!

override func viewDidLoad() 
    super.viewDidLoad()

    webView = WKWebView(frame:  self.view.frame)
    webView.navigationDelegate = self

    let url = NSURL (string: "https://google.com");
    let request = NSURLRequest(url: url! as URL)
    webView.load(request as URLRequest)

    self.view.addSubview(webView)

    self.view.sendSubview(toBack: webView)




func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) 

    webView.evaluateJavaScript("document.documentElement.outerHTML.toString()", completionHandler:  (html: AnyObject?, error: NSError?) in
        print(html!)
         as? (Any?, Error?) -> Void)

    print("didFinish")


【问题讨论】:

【参考方案1】:

evaluateJavaScriptWKWebView 一起使用有点棘手。

由于我认为这个答案对很多人都有用,而不是用简短的代码 sn-p 和您需要实现 WKScriptMessageHandler 的评论来解决您的具体问题,我将发布一个完整的、完整的示例,您可以使用该示例查看所有内容如何协同工作。

要使用它,请在 Xcode 中创建一个“单一视图应用程序”ios 项目并将其粘贴到默认的 ViewController.swift 文件上。

//
//  WebViewController.swift
//  WKWebViewExample
//
//  Created by par on 4/2/17.
//  Copyright © 2017 par. All rights reserved.  MIT License.
//

import UIKit
import WebKit

class ViewController: UIViewController 
    override func viewDidLoad() 
        super.viewDidLoad()

        let webViewController = WebViewController()

        // install the WebViewController as a child view controller
        addChildViewController(webViewController)

        let webViewControllerView = webViewController.view!

        view.addSubview(webViewControllerView)

        webViewControllerView.translatesAutoresizingMaskIntoConstraints = false
        webViewControllerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        webViewControllerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        webViewControllerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        webViewControllerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true

        webViewController.didMove(toParentViewController: self)
    


class WebViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler 
    private var webView: WKWebView!
    private var webViewContentIsLoaded = false

    init() 
        super.init(nibName: nil, bundle: nil)

        self.webView = 
            let contentController = WKUserContentController()

            contentController.add(self, name: "WebViewControllerMessageHandler")

            let configuration = WKWebViewConfiguration()
            configuration.userContentController = contentController

            let webView = WKWebView(frame: .zero, configuration: configuration)
            webView.scrollView.bounces = false
            webView.navigationDelegate = self

            return webView
        ()
    

    required init?(coder aDecoder: NSCoder)  fatalError("init(coder:) has not been implemented") 

    override func viewDidLoad() 
        super.viewDidLoad()

        view.addSubview(webView)

        webView.translatesAutoresizingMaskIntoConstraints = false
        webView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        webView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        webView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        webView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    

    override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(animated)

        if !webViewContentIsLoaded 
            let url = URL(string: "https://***.com")!
            let request = URLRequest(url: url)

            webView.load(request)

            webViewContentIsLoaded = true
        
    

    private func evaluateJavascript(_ javascript: String, sourceURL: String? = nil, completion: ((_ error: String?) -> Void)? = nil) 
        var javascript = javascript

        // Adding a sourceURL comment makes the javascript source visible when debugging the simulator via Safari in Mac OS
        if let sourceURL = sourceURL 
            javascript = "//# sourceURL=\(sourceURL).js\n" + javascript
        

        webView.evaluateJavaScript(javascript)  _, error in
            completion?(error?.localizedDescription)
        
    

    // MARK: - WKNavigationDelegate

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) 
        // This must be valid javascript!  Critically don't forget to terminate statements with either a newline or semicolon! 
        let javascript =
            "var outerHTML = document.documentElement.outerHTML.toString()\n" +
            "var message = \"type\": \"outerHTML\", \"outerHTML\": outerHTML \n" +
            "window.webkit.messageHandlers.WebViewControllerMessageHandler.postMessage(message)\n"

        evaluateJavascript(javascript, sourceURL: "getOuterHMTL")
    

    // MARK: - WKScriptMessageHandler

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) 
        guard let body = message.body as? [String: Any] else 
            print("could not convert message body to dictionary: \(message.body)")
            return
        

        guard let type = body["type"] as? String else 
            print("could not convert body[\"type\"] to string: \(body)")
            return
        

        switch type 
        case "outerHTML":
            guard let outerHTML = body["outerHTML"] as? String else 
                print("could not convert body[\"outerHTML\"] to string: \(body)")
                return
            
            print("outerHTML is \(outerHTML)")
        default:
            print("unknown message type \(type)")
            return
        
    

【讨论】:

您不认为这会在代码中添加额外的文件,并且在项目成本基于 LoC 时可能不是首选。无论如何+1! 很好的答案有效,帮助我登录到我需要的网络。问题,然后在这个站点登录后出现另一个网页,我需要在那里运行一个javascript,输入姓氏并返回?想法在哪里/如何做到这一点?你可以给我发电子邮件是最好的。谢谢迈克 嗨@Mike - 我担心你的问题对于 cmets 中的答案来说太复杂了,并且对于这个特定的问题和答案来说并不是真正的主题。很大程度上取决于登录后出现的网页以及如何与之交互。我建议您在 *** 上提出一个新问题,并向人们展示您迄今为止的想法。希望您能得到许多有用的答案!【参考方案2】:

我知道已经有一段时间没有回答这个问题了,我发现这对我来说真的不起作用。我改用下面的。

在添加 setTimeout() 函数之前,我无法让 evaluateJavaScript 工作。值得一提的是我的代码如下。

webView.evaluateJavaScript("setTimeout(function() 
// Do something here
,10);")  (result1, error) in
            if error == nil 
                print(result1 ?? "")
            
        

【讨论】:

以上是关于WKWebView evaluateJavaScript 不返回 html的主要内容,如果未能解决你的问题,请参考以下文章

iOS wkwebview怎么写localStorage

已有iOS项目集成cordova并使用wkwebview

滚动视图中的 WKWebView

WKWebView 那些坑

WKWebView 那些坑

WKWebView 可水平滚动