WKWebView的使用

WKWebView是iOS8.0之后引入的,不再打算适配iOS7.0的小伙伴可以尝试使用一下这个WKWebView这个控件。

WKWebView与UIWebView的一个简单的对比
  • UIWebView的缺点:
    加载速度慢、占用内存多,如果加载网页过多,还可能因为过量占用内存而被系统kill掉

  • WKWebView的优点:
    1.在性能、稳定性、内存占用上有很大的提升。
    2.允许Javascript的Nitro库加载并使用(UIWebView中限制)
    3.支持更多的HTML5特性
    4.高达60fps的滚动刷新率以及内置手势;
    5.可以监控网络加载的进度,终于可以实现一个真的进度条了
    利用WKWebView实现类似微信一样的加载网页的进度条
    对H5界面的影响:
    1.在UIWebView中,html5的点击事件会有300ms的延迟,在WKWebView中这个问题得到了很好的解决,前提是需要将
    user-scalable = 0 的页面,WKWebView将会移除300ms的click事件延迟
    2.滑动页面js被挂起的问题也被修复了。
    3.WKWebview中,页面A跳转到页面B再返回页面A后不会重新执行Script和Ajax(也不会触发页面reload),但会触发页面的pageshow pageHide等事件。
    4.WKWebview中,在页面弹出输入键盘后,会触发JQuery的resize事件,而在UIWebView下不会。
    5.WKWebview中,window unload 事件在只有刷新才能触发,退出页面或者跳转到其他页面都无法触发。
    6.WKWebview中,极少数情况下某些特殊实现的页面点击事件会失效。
    在具体使用WKWebView的时候,需要进行一些适配,具体可以参考微信的适配文档:iOS WKWebview 网页开发适配指南

WKWebView的使用介绍
  • 首先要导入WebKit框架
  • WKWebView提供的与JS交互的方法
//执行js语句
 open func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Swift.Void)? = nil)
  • WKWebView提供了两个代理:navigationDelegate和UIDelegate。

注意:在以后的开发中,如果遇到代理方法的block回调是handler的一定要实现这个回调,否则会直接报错。

  • WKNavigationDelegate和WKUIDelegate的代理方法
//MARK:在发送请求之前,决定是否跳转
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    decisionHandler(.allow)
}
//MARK:收到响应后决定是否跳转
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    decisionHandler(.allow)
}
//MARK:接收到服务器跳转请求之后调用
func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
}

//MARK:页面开始加载时调用
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
}
//MARK:当内容开始返回时调用
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
}
//MARK:页面加载完成之后调用
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
//MARK:页面加载失败时调用
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
}
在WKWebview中,js的alert是不会出现任何内容的,你必须重写WKUIDelegate委托的runJavaScriptAlertPanelWithMessage message方法,自己处理alert。类似的还有Confirm和prompt也和alert类似,这里我只以alert为例。
//接收js alert
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
    completionHandler()
    printlndebug("alert:\(message)")
    //        let alert = UIAlertController(title: "", message: message, preferredStyle: .alert)
    //        alert.addAction(UIAlertAction(title: "确定", style: .default, handler: nil))
    //        self.present(alert, animated: true, completion: nil)
}
//接收js confirm
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
    //        let alert = UIAlertController(title: "", message: message, preferredStyle: .alert)
    //        let ok = UIAlertAction(title: "确定", style: .default) { (action) in
    //            completionHandler(true)
    //        }
    //        let cancel = UIAlertAction(title: "取消", style: .cancel) { (action) in
    //            completionHandler(false)
    //        }
    //        alert.addAction(ok)
    //        alert.addAction(cancel)
    //        self.present(alert, animated: true, completion: nil)
    printlndebug("confirm:\(message)")
}
//接收js prompt
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
    printlndebug("prompt:\(prompt)")
    
}
关于WKWebView的清理缓存问题

WKWebView是在ios8.0之后推出的,但是清理缓存的功能是在ios9.0之后推出的。所以要判断一下系统的版本,否则可能会导致程序崩溃

        if #available(iOS 9.0, *) {
            let types:Set = [WKWebsiteDataTypeMemoryCache,WKWebsiteDataTypeDiskCache]
            let dateFrom = Date(timeIntervalSince1970: 0)
            WKWebsiteDataStore.default().removeData(ofTypes: types, modifiedSince: dateFrom, completionHandler: { 
        })
        } else {
            // Fallback on earlier versions
            let libraryPath = NSSearchPathForDirectoriesInDomains(.userDirectory, .userDomainMask, true).last
            if let cookies = libraryPath?.appending("/Cookies") {
                do {
                    try FileManager.default.removeItem(atPath: cookies)
                } catch {
                }
            }
        }
关于WKWebView的跨域问题:

WebKit框架对跨域进行了安全性检查限制,不允许跨域,比如从一个 HTTP 页对 HTTPS 发起请求是无效的(有一个界面要跳到支付宝页面去支付,死活没反应)
但是WebKit对跨域进行了安全检查限制,不允许跨域,所以要对需要跨域的链接进行单独处理。

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    var policy = WKNavigationActionPolicy.allow
    if let url = navigationAction.request.url,WKNavigationType.linkActivated == navigationAction.navigationType && url.scheme == "https" {
        UIApplication.shared.open(url, options: [:], completionHandler: { (flag) in
            policy = WKNavigationActionPolicy.cancel
        })
    }
    decisionHandler(policy)
}

更多关于使用WKWebView需要注意的坑,请参考:WKWebView 那些坑

参考文档:
1.UIWebView和WKWebView的使用及js交互
2.WKWebView微信适配
3.iOS9WKWebView清除缓存
4.WKWebView走过的10个坑

你可能感兴趣的:(WKWebView的使用)