WKWebView

2018-04-18  本文已影响0人  古月思吉
  1. BaseWebViewController:
class BaseWebViewController: BaseViewController {
    
    //MARK: - 属性
    public lazy var webView: WKWebView = {
        let configuration = WKWebViewConfiguration.init()
        let webView = WKWebView.init(frame: CGRect.init(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height), configuration: configuration)
        webView.navigationDelegate = self
        webView.uiDelegate = self
        return webView
    }()
    
    private lazy var progressView: UIProgressView = {//进度条
        let progressView = UIProgressView.init(frame: CGRect.init(x: 0, y: 0, width: view.bounds.width, height: 3.0))
        progressView.progress = 0.0
        progressView.tintColor = UIColor.red
        return progressView
    }()

    private var urlString: String?//url地址字符串
    private var isProgressBarHidden: Bool = false//是否隐藏ProgressView
    private var hasLoadedSuccess: Bool = false//是否已经加载成功过
    
    private let JSHandlerName_share = "Share"//JS调iOS-分享
    
    //MARK: - 生命周期
    override func viewDidLoad() {
        super.viewDidLoad()

        self.prepareUI()
    }
    
    deinit {
        if !isProgressBarHidden {
            self.webView.removeObserver(self, forKeyPath: "estimatedProgress")
        }
        self.webView.navigationDelegate = nil
        self.webView.navigationDelegate = nil
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    //MARK: - 其他
    
    /// webViewController的初始化配置
    ///
    /// - Parameters:
    ///   - urlString: 地址字符串
    ///   - isNavigationBarHidden: 是否隐藏navigationBar
    ///   - isProgressBarHidden: 是否隐藏progressBar
    public func config(urlString:String, isNavigationBarHidden:Bool = false, isProgressBarHidden:Bool = false) {
        self.urlString = urlString
        self.isNavigationBarHidden = isNavigationBarHidden
        self.isProgressBarHidden = isProgressBarHidden
    }

    /// UI初始化
    private func prepareUI() {
        if !isProgressBarHidden {
            self.webView.addSubview(self.progressView)//添加进度条
            self.webView.addObserver(self, forKeyPath: "estimatedProgress", options: NSKeyValueObservingOptions.new, context: nil)//进度监听
        }
        self.view.addSubview(self.webView)
        self.addJSHandlerNames()
        self.loadH5()
        
        if !isNavigationBarHidden {
            //返回按钮点击事件自定义
            self.customGoBack { [weak self] in
                if (self?.webView.canGoBack)! {
                    self?.webView.goBack()
                } else {
                    self?.navigationController?.popViewController(animated: true)
                }
            }
        }
    }
    
    /// 加载H5
    private func loadH5() {
        guard self.urlString != nil else {
            return
        }
        let url = NSURL.init(string: self.urlString!)
        guard url != nil else {
            return
        }
        let request = NSURLRequest.init(url: url! as URL)
        self.webView.load(request as URLRequest)
    }
    
    /**获取监听的代理方法*/
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "estimatedProgress" && !isProgressBarHidden {
            self.progressView.alpha = 1.0
            self.progressView.setProgress(Float(webView.estimatedProgress), animated: true)
            if(self.webView.estimatedProgress >= 1.0) {//进度条的值最大为1.0
                UIView.animate(withDuration: 0.3, delay: 0.1, options: UIViewAnimationOptions.curveEaseInOut, animations: { () -> Void in
                    self.progressView.alpha = 0.0
                }, completion: { (finished:Bool) -> Void in
                    self.progressView.progress = 0
                })
            }
        }
    }
    
}

2.WKNavigationDelegate:

//MARK: - WKNavigationDelegate
extension BaseWebViewController: WKNavigationDelegate {
    
    //MARK: - 导航监听
    
    /**在发送请求之前,决定是否跳转*/
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        //...(实现url重定向)
        let urlStr = navigationAction.request.url?.absoluteString
        print(urlStr!)
        decisionHandler(.allow)
    }
    
    /**身份验证*/
    func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil)//设置为nil,不要证书验证
    }
    
    /**在收到响应后,决定是否跳转*/
    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        let urlStr = navigationResponse.response.url?.absoluteString
        print(urlStr!)
        decisionHandler(.allow)
    }
    
    /**接收到服务器跳转请求之后调用*/
    func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
        
    }
    
    /**WKNavigation导航错误*/
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        AJAlertTool.showCancel(message: error.localizedDescription)
        NetworkDataViewManager.addNoNetworkView(toView: self.view, refreshBlock: { [weak self] in
            if self?.hasLoadedSuccess == true {
                self?.webView.reload()//如果网络加载成功过,直接reload
            } else {
                self?.loadH5()//如果网页加载一次都没有成功过,则重新发起请求
            }
        })
    }
    
    /**WKWebView终止*/
    func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
        
    }
    
    //MARK: - 页面内监听
    
    /**页面开始加载时调用*/
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        
    }
    
    /**当内容开始返回时调用*/
    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        
    }
    
    /**页面加载完成之后调用*/
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        NetworkDataViewManager.removeNoNetworkView(fromView: self.view)
        if !isNavigationBarHidden {
            self.navigationItem.title = self.webView.title
        }
        self.hasLoadedSuccess = true
    }
    
    /**页面加载失败时调用*/
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        AJAlertTool.showCancel(message: error.localizedDescription)
        NetworkDataViewManager.addNoNetworkView(toView: self.view, refreshBlock: { [weak self] in
            if self?.hasLoadedSuccess == true {
                self?.webView.reload()//如果网络加载成功过,直接reload
            } else {
                self?.loadH5()//如果网页加载一次都没有成功过,则重新发起请求
            }
        })
    }
    
}

3.WKUIDelegate:

//MARK: - WKUIDelegate
extension BaseWebViewController: WKUIDelegate {
    
    /**WKWebView创建初始化加载的一些配置*/
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        //为防止系统阻止不安全的连接,需要实现下面的方法
        //如果目标主视图不为空,则允许导航
        if !(navigationAction.targetFrame?.isMainFrame != nil) {
            self.webView.load(navigationAction.request)
        }
        return nil
    }
    
    /**JS提示框(ok)处理*/
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        AJAlertTool.showOK(message: message) {
            completionHandler()
        }
    }
    
    /**JS确认弹窗(cancel & ok)处理*/
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        AJAlertTool.showCancelOK(title: nil, message: message, cancelTitle: "取消", cancelBlock: {
            completionHandler(false)
        }, okTitle: "确定") {
            completionHandler(true)
        }
    }
    
    /**js中的文本输入处理*/
    func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        AJAlertTool.showTextInput(title: prompt, message: nil, defaultTextFieldMessage: defaultText, textFieldPlaceholder: nil, cancelTitle: "取消", cancelBlock: nil, okTitle: "确定") { (textFieldText) in
            completionHandler(textFieldText)
        }
    }
    
}

4.WKScriptMessageHandler:

//MARK: - WKScriptMessageHandler
extension BaseWebViewController:WKScriptMessageHandler {
    
    /**从web界面中接收到一个脚本时调用*/
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == JSHandlerName_share {
            //分享相关操作...
        }
        //...
    }
    
}

5.JS交互相关:

//MARK: - JS交互相关
extension BaseWebViewController {
    
    //MARK: - JS 调用 OC
    
    /// 添加处理脚本
    private func addJSHandlerNames() {
        self.webView.configuration.userContentController.add(self, name: JSHandlerName_share)
        //...
    }
    
    
    //MARK: - OC 调用 JS
    
    /// 调用JS处理的事件1
    private func JSAction1() {
        //让JS调用HTML文件中的“show()”函数
        self.webView.evaluateJavaScript("show()", completionHandler: { (response, error) in
            //(处理JS执行“show()”函数之后的操作)
        })
    }
    
    //...
    
}

6.如何获取H5网页的title、logo?

/**页面加载完成之后调用*/
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        NetworkDataViewManager.removeNoNetworkView(fromView: self.view)
      
        //获取标题
        self.webView.evaluateJavaScript("document.title", completionHandler: { (response, error) in
            let linkTitle = response as? String
        })
        //获取logo
        self.webView.evaluateJavaScript("document.querySelector('link[rel=\"shortcut icon\"]').href", completionHandler: { (response, error) in
            let linkLogo = response as? String
        })
        
    }

参考文章:
https://www.jianshu.com/p/60b9681dd8d2
https://www.jianshu.com/p/ab58df0bd1a1

上一篇下一篇

猜你喜欢

热点阅读