Swift WKWebView与JS交互

本篇是基于Swift4.0为大家介绍下WKWebView与JS的交互.

OC版本请跳转OC WKWebView与JS交互.

1.WKWebView调用JS

WKWebView可以直接使用下放方法调用JS.

open func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Swift.Void)? = nil)

举个例子.我们需要获取,一段HTML标签的内容.
HTML标签内容如下:


我们需要在网页加载完成的时候进行获取,那么我们首先服从WKNavigationDelegate协议,并且设置代理.然后在如下代理方法中执行JS方法.

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
      /// wkWebView调用js方法
      let js = "document.getElementsByName('input')[0].attributes['value'].value"
      wkWebView.evaluateJavaScript(js) { (response, error) in
            print("response:", response ?? "No Response", "\n", "error:", error ?? "No Error")
      }
}

通过以上操作就成功获取到input标签的value属性值了.如果报错,可以通过error进行相应的错误处理.

2.JS调用Swift

当JS端想传一些数据给Swift.那它们会调用下方方法来发送.

window.webkit.messageHandlers.<方法名>.postMessage(<数据>)

上方代码在JS端写会报错,导致网页后面业务不执行.可使用try-catch执行.

try {
      //使用此方法,会报错,因此使用try-catch
      window.webkit.messageHandlers.<方法名>.postMessage(<数据>);
 } catch(error) {
      console.log('WKWebView post message');
}

那么下面就要在Swift接收JS传来的数据了.
我们可以在WKScriptMessageHandler协议中的方法来检测传来的数据.
首先要对WKWebView添加方法名检测的方法.

wkWebView.configuration.userContentController.add(self, name: <方法名>)

此时的代理对象为self(控制器本身),会存在内存泄露问题

然后服从WKScriptMessageHandler协议,在它的协议方法中我们就可以检测到传来的数据啦.

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
      print("传来的数据为", message.body)
}

3.JS调用Swift - 内存泄露

上方已经讲到,将WKScriptMessageHandler设置为self,会造成内存泄露问题.运行一下上述方法,会发现WKWebView所在控制器不走deinit()方法.
我们可以创建一个专门用于检测传来数据的代理转接下.
代码如下:

import UIKit
import WebKit

class WeakScriptMessageDelegate: NSObject, WKScriptMessageHandler {
    weak var scriptDelegate: WKScriptMessageHandler?
    
    init(_ scriptDelegate: WKScriptMessageHandler) {
        self.scriptDelegate = scriptDelegate
        super.init()
    }
    
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        scriptDelegate?.userContentController(userContentController, didReceive: message)
    }
    
    deinit {
        print("WeakScriptMessageDelegate is deinit")
    }
}

将它作为WKScriptMessageHandler的代理,进行转接.
使用时只需要将原本添加检测方法中的self,替换为WeakScriptMessageDelegate的实例就行了.

wkWebView.configuration.userContentController.add(WeakScriptMessageDelegate.init(self), name: <方法名>)

现在解决了控制器的回收,那么我们的转接代理同样也要释放.
在控制器的deinit()方法将其释放一下就OK啦.

deinit {
      wkWebView.configuration.userContentController.removeScriptMessageHandler(forName: <方法名>)
      print("WKWebViewController is deinit")
}

你可能感兴趣的:(Swift WKWebView与JS交互)