iOS development talk WKWebView adds click events to H5 web images to achieve native image preview

     This is the continuation of the comic WKWebView. In this article, we mainly implement the need to inject Js into WKWebView to achieve click-to-image preview. Without further ado, let’s take a look at the finished product:

To realize this requirement is undoubtedly to realize the interactive operation between Js and WKWebView, including value transfer and mutual calling. There are tons of articles on this topic on the Internet, but only a few are used in this article: inject Js to dynamically add click events to img, pass values ​​to WKWebView, and natively respond to events to obtain parameters to implement preview. The final point is to pass values. . To sort out the ideas, you can use Scheme, request interception, JavaScriptCore and WKScriptMessageHandler in the app.

       Here are many articles on the two sentences. Many articles on the Internet did not test the original copy. For example: DocumentView.webview.mainframe.javaScriptContext is available in UIWEBVIEW, but directly collapsed in WKWebview. This is a necessary part of using JavaScriptCore, and this pit wasted a lot of my time. Therefore, the only two options here are request interception and WKScriptMessageHandler. WKScriptMessageHandler is mainly used in this article. The main reference codes are as follows:

1. Define WKWebView and specify WKNavigationDelegate protocol

private lazy var wkWebView:WKWebView = {[unowned self] in
        let _wk = WKWebView.init(frame: .zero)
        _wk.navigationDelegate = self
       
        return _wk
   }()

2. Implement the WKNavigationDelegate protocol and inject Js events (note: when injecting the jQuery library, you need to download the file from the jQuery official website and add it to the project, otherwise it cannot be injected)


//MARK: - WKNavigationDelegate
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.15) {
            self.pourIntoJsFor(WKWebView: webView)
        }
    }
    
/// 注入Js
private func pourIntoJsFor(WKWebView webView:WKWebView){
        //注入jQuery库(由于很多H5使用的VUE或者Ajax等技术异步加载渲染,因此此处需要借助jQuery库给一步渲染的img动态绑定事件,如果是静态H5或者H5中已有该文件则无需注入jQuery库)
        let jQueryPath = Bundle.main.path(forResource: "jQuery-3.5.1.mini", ofType: "js")
        if let jQueryDat:Data = try? Data.init(contentsOf: URL.init(fileURLWithPath: jQueryPath!)) {
            webView.evaluateJavaScript(String.init(data: jQueryDat, encoding: .utf8)!) { [self] (_:Any?, error:Error?) in
                print("jQuery注入\(error == nil ? "成功":"失败")")
                
                if error == nil {
                    //注入图片点击的脚本事件
                    let strJs = String.init(format:"var imgUrl='';var objs=document.getElementsByTagName('img');for(var i=0;i<objs.length;i++){imgUrl+=objs[i].src+',';$(objs[i]).on('click',function(){window.webkit.messageHandlers.%@.postMessage({curl:this.src,imgUrl});});}",js_message_handler_name)

                    print("strJs:\(strJs)")
                    webView.evaluateJavaScript(strJs) { (_:Any?, error:Error?) in
                        print("Js注入\(error == nil ? "成功":"失败")")
                    }
                }
            }
        }
    }

3. Initialize and add Js injection object

    private let js_message_handler_name = "CommunityJSObj"

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.addSubview(self.wkWebView)
        
        //注意在这里注入JS对象名称
        self.wkWebview.configuration.userContentController.add(self, name: js_message_handler_name)
    }

Note:window.webkit.messageHandlers.xxx.postMessage is a specific writing method with consistent upper and lower case. The xxx in the middle is the custom injection object name. In this article, it is defined by js_message_handler_name constant object

If there are no parameters, you can write like this:

window.webkit.messageHandlers.xxx.postMessage();

A parameter can be written like this:

window.webkit.messageHandlers.xxx.postMessage({body:parameter value 1});

Or write like this:

window.webkit.messageHandlers.xxx.postMessage({parameter name 1: parameter value 1});

Multiple parameters can be written like this:

window.webkit.messageHandlers.xxx.postMessage({parameter name 1: parameter value 1, parameter value 2,...});

4. Implement the WKScriptMessageHandler protocol to respond to the img click event injected in H5

//MARK: - WKScriptMessageHandler
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            
        /**
         message:WKScriptMessage对象
         message.name:注入JS对象名称
         message.body:js回传参数
         */
        print(message)
        print(message.name)
        print(message.body)
        
        //图片预览
        if message.name == js_message_handler_name {
            guard let _dicTemp = message.body as? [String:String] else {
                return
            }
            
            guard let curl = _dicTemp["curl"],let imgUrls:[String] = _dicTemp["imgUrl"]?.split(separator: ",").compactMap({ "\($0)" }) else {
                return
            }
            
            print("curl:\(curl),imgUrls:\(imgUrls)")         
        }
  }

The response information when clicking on the image is printed as follows:

5. Destroy the object

deinit {
        self.wkWebview.configuration.userContentController.removeScriptMessageHandler(forName:js_message_handler_name)
        
        //清除wkWebView缓存
        let dt = WKWebsiteDataStore.allWebsiteDataTypes()
        let date = Date.init(timeIntervalSince1970: .zero)
        WKWebsiteDataStore.default().removeData(ofTypes: dt, modifiedSince: date) {
            print("wkWebView 缓存清除Ok")
        }
    }

In addition, the topic of request interception will be written in a blog later. This method can also be used to implement this function.

The end of this article! That’s all the above content. If you have any questions, please leave a message.

 

Guess you like

Origin blog.csdn.net/yimiyuangguang/article/details/114642196