学习笔记:WKWebView的简单使用(Swift)

一、WKWebView:

在WWDC2014中,随着iOS 8一起推出的新控件,解决并完善了UIWebView存在的内存和加载速度等问题,在苹果官方文档中也在极力推荐使用WKWeb来替换UIWeb,只要你的APP最低支持版本是8.0:(苹果官方文档


二、使用:

    1、初始化,与UIWeb一样,唯一的就是加载本地html只有在9之后才可以使用

    let webConfig = WKWebViewConfiguration();
    let webView = WKWebView(frame: CGRect.zero, configuration: webConfig)
    webView.frame = self.webPlaceholderView.bounds;
    webView.navigationDelegate = self
    webView.uiDelegate = self
    webView.load(URLRequest.init(url: URL.init(string: "file:///Users/liuxinning/Desktop/Projects/HTML/Cyning/index.html")!))
    // 直接记载本地html方法在9之后才支持,8的时候需要用RULRequest曲线救国下
     // self.webView.loadFileURL(<#T##URL: URL##URL#>, allowingReadAccessTo: <#T##URL#>)
2、在加载过程中会在相应的时机出发对应的代理方法(如果你设置并实现的话)
navigationDelegate 主要可以监控着整个web的生命周期 (NavigationDelegate使用说明)
uiDelegate 主要监控web的js交互,从而用于与APP进行对应的交互 (UIDelegate使用说明)
3、关于 WKWebViewConfiguration (TODO)

//
//  RouteWebViewController.swift
//  TestAnyThing
//
//  Created by 刘新宁 on 2017/2/15.
//  Copyright © 2017年 刘新宁. All rights reserved.
//

import UIKit
import WebKit


class RouteWebViewController: UIViewController,WKNavigationDelegate,WKUIDelegate,UIAlertViewDelegate  {
    
    lazy var alertViewController : UIAlertController = {
        return UIAlertController.init(title: "我是一个VC", message: "message", preferredStyle: UIAlertControllerStyle.alert)
    }()
    @IBOutlet weak var navRightButton: UIButton!
    
    var OKAlertAction : UIAlertAction = UIAlertAction()
    
    var CancelAlertAction : UIAlertAction = UIAlertAction()
    
    var clickButtonTime : Int = 0
    
    let webView : WKWebView = {
        let webConfig = WKWebViewConfiguration();

        let webView = WKWebView(frame: CGRect.zero, configuration: webConfig)
        
        return webView
    }()
    override func viewDidLoad() {
        super.viewDidLoad()
        self.__setupWebView()
    }
    @IBOutlet weak var webPlaceholderView: UIView!

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    func __setupWebView(){
        self.webView.frame = self.webPlaceholderView.bounds;
        self.webView.navigationDelegate = self
        self.webView.uiDelegate = self
        
        self.webView.load(URLRequest.init(url: URL.init(string: "file:///Users/liuxinning/Desktop/Projects/HTML/Cyning/index.html")!))
        
    }
    //MARK: - WKUIDelegate
    /**
     Description
     
     - parameter webView:           webView description
     - parameter message:           message description
     - parameter frame:             frame description
     - parameter completionHandler: completionHandler必须执行
     */
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        debugPrint("confirm message : \(message)")
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
        completionHandler(true)
    }
    /**
     Description
     
     - parameter webView:           webView description
     - parameter message:           message description
     - parameter frame:             frame description
     - parameter completionHandler: completionHandler必须执行
     */
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
        debugPrint("webView run alert JS: \(message) ")
        completionHandler()
    }
    
    func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        debugPrint("webView run prompt JS: \(prompt) defaultText:\(defaultText)")
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
        
        completionHandler("testText")
    }
    /**
     创建一个新的 webView
     
     - parameter webView:          webView description
     - parameter configuration:    configuration description
     - parameter navigationAction: navigationAction description
     - parameter windowFeatures:   windowFeatures description
     
     - returns: return value description
     */
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
       debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
        
        
        return webView
    }
    
    /**
     9.0 later
     
     - parameter webView: webView description
     */
    @available(iOS 9.0, *)
    func webViewDidClose(_ webView: WKWebView) {
       debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
    }
    /*
     以下方法均为10.0之后
     */
    
    @available(iOS 10.0, *)
    func webView(_ webView: WKWebView, shouldPreviewElement elementInfo: WKPreviewElementInfo) -> Bool {
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
        return true
    }
    
    @available(iOS 10.0, *) 
    func webView(_ webView: WKWebView, previewingViewControllerForElement elementInfo: WKPreviewElementInfo, defaultActions previewActions: [WKPreviewActionItem]) -> UIViewController? {
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
        return self
        
    }
    
    @available(iOS 10.0, *)
    func webView(_ webView: WKWebView, commitPreviewingViewController previewingViewController: UIViewController) {
       debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
    }
    
    
    
    //MARK: - WKNavigationDelegate
    
    /**
     执行层级:①
     webView发起请求之前调用
     allow后才会进行后面的代理方法
     decisionHandler 必须执行
     - parameter webView:          响应webView
     - parameter navigationAction: 包含响应事件的信息对象
     - parameter decisionHandler:  回调block,参数:allow or cancel
     */
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
       let urlString = navigationAction.request.url?.absoluteString
        if self.interceptForLocalRouter(navigationAction: navigationAction) == true{
            decisionHandler(.cancel)
        }else if (urlString?.hasPrefix("https") == true ||
                  urlString?.hasPrefix("http") == true  ||
                  urlString?.hasPrefix("file") == true){
           decisionHandler(.allow)
        }else {
           decisionHandler(.cancel)
        }
        debugPrint("urlString : \(urlString)")
    }
    /**
     执行层级:③
     URL响应正确,接收到相应数据后,决定是否跳转
     decisionHandler 必须执行
     - parameter webView:            响应webView
     - parameter navigationResponse: 请求地址
     - parameter decisionHandler:    回调block,参数:allow or cancel
     */
    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
    /*  //
        let alertView = UIAlertController.init(title: "请求前确认", message: "是否允许请求:\n\(navigationResponse.response.url)", preferredStyle: UIAlertControllerStyle.actionSheet)
        let OKAction  = UIAlertAction.init(title: "确定", style: UIAlertActionStyle.destructive, handler: { (alertAction) in
            decisionHandler(WKNavigationResponsePolicy.allow)
        })
        let cancelAction = UIAlertAction.init(title: "取消", style: UIAlertActionStyle.default, handler: { (alertAction) in
            decisionHandler(WKNavigationResponsePolicy.cancel)
        })
        alertView.addAction(OKAction)
        alertView.addAction(cancelAction)
        
        self.OKAlertAction = OKAction
        self.CancelAlertAction = cancelAction
        self.alertViewController = alertView;
        
        self.present(alertView, animated: true) {
            
        }
        */
        
        decisionHandler(WKNavigationResponsePolicy.allow)
        
    }
    /**
     执行层级:②
     允许请求后开始
     
     - parameter webView:    响应webView
     - parameter navigation: navigation
     */
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
    }
    /**
     主机地址被重定向时调用
     
     - parameter webView:    webView description
     - parameter navigation: navigation description
     */
    func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
    }
    /**
     执行层级:④
     页面加载失败时调用
     
     - parameter webView:    响应webView
     - parameter navigation: navigation
     - parameter error:      error
     */
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        debugPrint(#function + "\nerror: \(error.localizedDescription)")
    }
    /**
     执行层级:④
     当内容开始返回时调用
     
     - parameter webView:    webView description
     - parameter navigation: navigation description
     */
    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
        
    }
    /**
     执行层级:⑤
     内容接受完毕后(JS等执行完毕后,在此之前执行 WKUIDelegate 的对应方法)
     
     - parameter webView:    webView
     - parameter navigation: navigation
     */
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        if self.webView.canGoBack == true{
            self.navRightButton.titleLabel?.text = "后退"
        }else if self.webView.url != nil{
            self.navRightButton.titleLabel?.text = "刷新"
        }else {
            self.navRightButton.titleLabel?.text = ""
        }
        self.webPlaceholderView.addSubview(self.webView)
        self.navigationItem.title = webView.title;
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")

    }
    /**
     跳转失败时调用
     
     - parameter webView:    webView description
     - parameter navigation: navigation description
     - parameter error:      error description
     */
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
        
    }
    /**
     在访问资源的时候,如果服务器返回需要授权(提供一个NSURLCredential对象)
     
     - parameter webView:           webView description
     - parameter challenge:         challenge description
     - parameter completionHandler:   completionHandler description
     */
    func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        
        debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
        
        // 认证服务器证书
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            debugPrint("获得服务端证书认证!")
            completionHandler(.performDefaultHandling, nil)
            /*
             /*
                将服务端证书与本地证书对比
             */
            completionHandler(.performDefaultHandling, nil)
            let serverTrust:SecTrust = challenge.protectionSpace.serverTrust!
            let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0)!
            let remoteCertificateData
                = CFBridgingRetain(SecCertificateCopyData(certificate))!
            let cerPath = Bundle.main.path(forResource: "tomcat", ofType: "cer")!
            let localCertificateData = NSData(contentsOfFile:cerPath)!
            // 对比证书
            if (remoteCertificateData.isEqual(to: localCertificateData as Data) == true) {
             // 将客户端证书返回给服务端
                let credential = URLCredential.init(trust: serverTrust)
                challenge.sender?.use(credential,
                                      for: challenge)
                completionHandler(.useCredential,
                                  URLCredential.init(trust: challenge.protectionSpace.serverTrust!))
                
            } else {
             // 认证不通过取消请求
                completionHandler(.cancelAuthenticationChallenge, nil)
            }
             */
        }else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate{
            debugPrint("客户端证书认证!")
            //获取客户端证书相关信息
            
            completionHandler(.useCredential, nil);
        }else {
            debugPrint("其它情况(不接受认证)")
            completionHandler(.cancelAuthenticationChallenge, nil);
        }
        
    }
    /**
     9.0 later,web内容处理中断时会触发
     
     - parameter webView: webView description
     */
    @available(iOS 9.0, *)
    func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
       debugPrint("class: \(object_getClassName(self))" + #function + "LINE: \(#line)")
    }
    
    @IBAction func close(_ sender: UIButton) {
        self.navigationController?.dismiss(animated: true, completion: {
            
        })
    }
    
    @IBAction func refresh(_ sender: UIButton) {
        if self.webView.canGoBack == true{
            self.webView.goBack()
        }else if self.webView.url != nil{
            self.webView.reload()
        }
    }
    
    func interceptForLocalRouter(navigationAction: WKNavigationAction) -> Bool{
//        NSString *method = navigationAction.request.HTTPMethod.uppercaseString;
//        NSString *schema = navigationAction.request.URL.scheme;
        let urlString = navigationAction.request.url?.absoluteString
        let method = navigationAction.request.httpMethod?.uppercased()
        if urlString?.hasPrefix(LocalScheme) == true && method == "GET"{
            debugPrint("LocalScheme:\(LocalScheme) ")
            return GloberRouter.sharedGloberRouter.routeFullUrlString(urlString!)
        }
        return false
    }

}

具体使用的Demon(持续更新中): Demon(持续更新中)

       

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值