美文网首页IOS&Swift
Swift与JS通过WKWebView互调

Swift与JS通过WKWebView互调

作者: iOS祎 | 来源:发表于2020-12-24 10:13 被阅读0次

    创建WKWebView

    lazy var webView: WKWebView = {
        // 创建WKPreferences
        let preferences = WKPreferences()
        // 开启js
        preferences.javaScriptEnabled = true
        // 创建WKWebViewConfiguration
        let configuration = WKWebViewConfiguration()
        // 设置WKWebViewConfiguration的WKPreferences
        configuration.preferences = preferences
        // 创建WKUserContentController
        let userContentController = WKUserContentController()
        // 配置WKWebViewConfiguration的WKUserContentController
        configuration.userContentController = userContentController
        // 给WKWebView与Swift交互起一个名字:callbackHandler,WKWebView给Swift发消息的时候会用到
        // 此句要求实现WKScriptMessageHandler协议
        configuration.userContentController.add(self, name: "callbackHandler")
    
        // 创建WKWebView
        var webView = WKWebView(frame: self.view.frame, configuration: configuration)
        // 让webview翻动有回弹效果
        webView.scrollView.bounces = true
        // 只允许webview上下滚动
        webView.scrollView.alwaysBounceVertical = true    
        // 此句要求实现WKNavigationDelegate协议
        webView.navigationDelegate = self
    
        return webView
    }()
    

    创建HTML

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no"/>
        </head>
        <body>
            iOS传过来的值:<span id="name"></span>
            <button onclick="responseSwift()">响应iOS</button>
            <script type="text/javascript">
                // 给Swift调用
                function sayHello(name) {
                    document.getElementById("name").innerHTML = name
                    return "Swift你好!"
                }
    
                // 调用Swift方法
                function responseSwift() {
                    // 这里的callbackHandler是创建WKWebViewConfiguration时定义的
                    window.webkit.messageHandlers.callbackHandler.postMessage("JS发送消息给Swift")
                }
            </script>
        </body>
    </html>
    

    实现两个协议

    WKNavigationDelegate:判断页面加载完成,只有在页面加载完成后才能在实现 Swift 调用 JS。WKWebView调用JS:

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        // sayHello()是JS的方法
        webView.evaluateJavaScript("sayHello('WebView你好!')") { (result, err) in
            print(result, err)
        }
    }
    

    WKScriptMessageHandler:JS 调用 Swift 时需要用到协议中的一个方法来。JS调用WKWebView:

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        print(message.body)
    }
    

    完整代码

    import UIKit
    import WebKit
    
    class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
    
        lazy var webView: WKWebView = {
            // 创建WKPreferences
            let preferences = WKPreferences()
            // 开启js
            preferences.javaScriptEnabled = true
            // 创建WKWebViewConfiguration
            let configuration = WKWebViewConfiguration()
            // 设置WKWebViewConfiguration的WKPreferences
            configuration.preferences = preferences
            // 创建WKUserContentController
            let userContentController = WKUserContentController()
            // 配置WKWebViewConfiguration的WKUserContentController
            configuration.userContentController = userContentController
            // 给WKWebView与Swift交互起一个名字:callbackHandler,WKWebView给Swift发消息的时候会用到
            // 此句要求实现WKScriptMessageHandler协议
            configuration.userContentController.add(self, name: "callbackHandler")
    
            // 创建WKWebView
            var webView = WKWebView(frame: self.view.frame, configuration: configuration)
            // 让webview翻动有回弹效果
            webView.scrollView.bounces = true
            // 只允许webview上下滚动
            webView.scrollView.alwaysBounceVertical = true
    
            // 此句要求实现WKNavigationDelegate协议
            webView.navigationDelegate = self
    
            return webView
        }()
    
        // 加载html
        let html = try! String(contentsOfFile: Bundle.main.path(forResource: "index", ofType: "html")!, encoding: String.Encoding.utf8)
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            title = "WebView与JS交互"
            view.addSubview(webView)
    
            webView.loadHTMLString(html, baseURL: nil)
        }
    
        // 加载完毕以后执行
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            // 调用JS方法
            webView.evaluateJavaScript("sayHello('WebView你好!')") { (result, err) in
                // result是JS返回的值
                print(result, err)
            }
        }
    
        // Swift方法,可以在JS中调用
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            print(message.body)
        }
    }
    

    补充

    拦截、并处理 alert()

    extension ViewController: WKUIDelegate {
    
        // 读取window.alert()
        func webView(_ webView: WKWebView,
                     runJavaScriptAlertPanelWithMessage message: String,
                     initiatedByFrame frame: WKFrameInfo,
                     completionHandler: @escaping () -> Void) {
            // 处理
        }
    }
    

    拦截、并处理 confirm()

    extension ViewController: WKUIDelegate {
        // 读取window.confirm()
        func webView(_ webView: WKWebView,
                     runJavaScriptConfirmPanelWithMessage message: String,
                     initiatedByFrame frame: WKFrameInfo,
                     completionHandler: @escaping (Bool) -> Void) {
    
            // 处理
        }
    }
    

    拦截、并处理 prompt()

    extension ViewController: WKUIDelegate {
        // 1.读取widnow.prompt()
        func webView(_ webView: WKWebView,
                     runJavaScriptTextInputPanelWithPrompt prompt: String,
                     defaultText: String?,
                     initiatedByFrame frame: WKFrameInfo,
                     completionHandler: @escaping (String?) -> Void) {
    
            //处理
        }
    }
    

    注入脚本

    // 创建WKUserContentController
    let userContentController = WKUserContentController()
    // 加载WKUserScript
    let userScript = loadUserScript(with: "html/local_script")
    // 注入WKUserScript
    userContentController.addUserScript(userScript)
    
    // addUserScript(_:) 接收一个WKUserScript对象
    func loadUserScript(with path: String) -> WKUserScript {
        // 加载本地js文件
        let filePath = Bundle.main.path(forResource: path, ofType: "js")
        // js文件内容
        var script:String?
    
        do {
            script = try String(contentsOfFile: filePath!, encoding: String.Encoding.utf8)
        }
        catch {
            print("Cannot Load File")
        }
    
        return WKUserScript(source: script!, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
    }
    

    防止内存泄漏

    deinit {
        userContentController.removeScriptMessageHandler(forName: "callbackHandler")
    }
    

    相关文章

      网友评论

        本文标题:Swift与JS通过WKWebView互调

        本文链接:https://www.haomeiwen.com/subject/ntopnktx.html