iOS精品文章iOS学习笔记

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

2017-10-11  本文已影响450人  c338388782c3

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上不去,放在码云上了

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

上一篇下一篇

猜你喜欢

热点阅读