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个坑