美文网首页iOS精品文章iOS学习笔记
WKWebView和JS交互(事件响应、参数传递)

WKWebView和JS交互(事件响应、参数传递)

作者: c338388782c3 | 来源:发表于2017-10-11 14:49 被阅读450次

    1、效果图

    native&web.gif

    Demo说明

    1. 点击网页的 弹框 按钮,触发js事件,Native通过web的代理方法响应
    2. 点击 分享 按钮,触发js事件,Native通过指定的handler类响应
    3. 点击 支付 按钮,触发js事件,Native通过制定的handler类响应,并获取参数
    4. 点击 ToWeb 按钮,触发Native事件,传递数组参数[1,2,3,4,5]给web,并显示在Input标签中

    2、WKWebview的介绍


    3、Native响应JS事件


    第一部分的1,2,3均属于这一范畴

    初始化WKWebview

     fileprivate lazy var web: WKWebView = {[unowned self] in
            
            let w = WKWebView(frame: CGRect.init(x: 0, y: 0, width: screenWidth, height: screenHeight))
            
            w.uiDelegate = self
            w.navigationDelegate = self
    
           //取web默认的配置选项
            let configuration = w.configuration
            
          //指定处理js事件的对象,该对象必须遵守WKScriptMessageHandler协议
            let hander = ScriptMessageHandler()
           
            hander.delegate = self
    
            configuration.userContentController.add(hander, name: Mobile)    
            return w
        }()
    
        deinit {
            //清除handler,保证释放
            web.configuration.userContentController.removeScriptMessageHandler(forName: Mobile)
        }
    

    handler对象(使用handle对象的目的是避免循环引用)

    class ScriptMessageHandler: NSObject {
        
        //设置代理,把捕获到的js事件转发给代理处理
        weak var delegate: WKScriptMessageHandler?
        
    }
    
    extension ScriptMessageHandler: WKScriptMessageHandler {
        
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            
            //代理响应捕获到的事件
            if let target = delegate{
                
                target.userContentController(userContentController, didReceive: message)
            }
        }
    }
    

    web点击弹框触发的方法+web代理WKUIDelegate的响应

        //js事件
        function presentAlert() {
            alert("I am alert");
        }
        //native事件,message参数的值是js中的"I am alert"
        func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
            
            showAlert(title: "Alert框", message: message)
            
            completionHandler()
        }
    

    web点击分享、支付触发的方法+handler响应+hander代理响应

        //1. js事件
        function share() {
            
            //这里可以传任何类型
            var param = {
                            message: "share",
                        };
    
            window.webkit.messageHandlers.Mobile.postMessage(param);
        }
    
    
        function pay() {
            //这里可以传任何类型
            var param = {
                            message: "pay",
                            param:888888
                        };
    
            window.webkit.messageHandlers.Mobile.postMessage(param);
        }
    
        //2. Native,handler响应
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            //代理响应捕获到的事件
            if let target = delegate{
                target.userContentController(userContentController, didReceive: message)
            }
        }
    
         //3.Native,handler的代理响应
         func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            
            guard message.name == Mobile else {
                print("不是绑定的响应对象")
                return
            }
    
            let dic = message.body as! Dictionary<String, Any>
            let title = dic["message"] as! String
            let message = dic["param"]
            
            showAlert(title: title, message: "\(message ?? "no Parameter")")
        }
    

    总结一下:

    1. 网页触发js事件,js中使用window.webkit.messageHandlers.Mobile.postMessage(param),传递一个任意类型的参数
    2. Native的handler接收到参数,解析参数。根据与前端协商好的方法名,决定事件处理

    4、Native调用JS事件

    第一部分的4属于这一范畴

    初始化WKWebview

     fileprivate lazy var web: WKWebView = {[unowned self] in
            
            let w = WKWebView(frame: CGRect.init(x: 0, y: 0, width: screenWidth, height: screenHeight))
            
            w.uiDelegate = self
            w.navigationDelegate = self
    
           //取web默认的配置选项
            let configuration = w.configuration
            
            let param = [1,2,3,4,5]
            
            //向网页注入一个用户脚本,点击rightIten时响应
            let script = WKUserScript(source: "function callJavaScript() {passAnArray(\(param));}", injectionTime: .atDocumentEnd, forMainFrameOnly: true)
            
            configuration.userContentController.addUserScript(script)  
            return w
        }()
    
        deinit {
            //清除所有注入的脚本
            web.configuration.userContentController.removeAllUserScripts()
        }
    

    点击导航栏的右侧按钮时,执行js方法,让网页中的js响应

        //传递一个数组给web
        @objc func rightClick(item: UIBarButtonItem) -> Void {
            
            //调用的JS方法,执行(注入脚本时,已指定该方法)
            let js = "callJavaScript()";
            
            //闭包处理js不通过的问题,并不是js代码的回调
            web.evaluateJavaScript(js) { (object, error) in
                
            }
        }
    

    总结一下:

    1. 先在Native的web配置中添加一个用户脚本,这个脚本会注入到网页中(脚本中要运行的函数名,参数,需要和前端商量好)
    2. 在Native中执行js代码,运行注入的脚本

    总结

    完整的代码在Demo里,三个文件

    1. 包含WKWebview的控制器
    2. 事件处理的handler
    3. 一个本地的html文件

    Demo下载地址,Github上不去,放在码云上了

    交互和传参不难,但是我理解时花了不少时间,总结了一下花时间的原因:

    • 不会前端,想到js响应事件就头疼
    • WKWebview引入了很多新的类,如WKUserScript,理解这些类的功能需要借助一点前端的知识
    • 大神们的博客没Demo参照的不直观。

    相关文章

      网友评论

        本文标题:WKWebView和JS交互(事件响应、参数传递)

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