WKWebView 的一些小总结

前端之家收集整理的这篇文章主要介绍了WKWebView 的一些小总结前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

WKWebView是  在iOS 8后推出要替代UIWebView。相对于成熟的UIWebView来讲,这个后生仔在使用上还是有点点小坑的~

使用

在初始化上,WKWebViewUIWebView 没有多大的差异。

// WKWebView
let wkWeb = WKWebView(frame: view.bounds)
// 一些代理
wkWeb.navigationDelegate = self
wkWeb.uiDelegate = self

// UIWebView
let web = UIWebView(frame: view.bounds)
// 一些代理
web.delegate = self

二者在初始化上还是蛮像的。一个图样的我。(逃

仔细翻开了WKWebView,发现其还提供一个初始化方法

public init(frame: CGRect,configuration: WKWebViewConfiguration)

也就是可以用WKWebViewConfigurationinit一个WKWebView

后面再继续港 WKWebViewConfiguration

那几个协议

WKNavigationDelegate

WKNavigationDelegate的协议方法还是挺多的。

// 1)接受网页信息,决定是否加载还是取消。必须执行肥调 decisionHandler 。逃逸闭包的属性
func webView(_ webView: WKWebView,decidePolicyFor navigationAction: WKNavigationAction,decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    print("\(#function)")
}

// 2) 开始加载
func webView(_ webView: WKWebView,didStartProvisionalNavigation navigation: WKNavigation!) {
    print("\(#function)")
}

// 3) 接受到网页 response 后,可以根据 statusCode 决定是否 继续加载。allow or cancel,必须执行肥调 decisionHandler 。逃逸闭包的属性
func webView(_ webView: WKWebView,decidePolicyFor navigationResponse: WKNavigationResponse,decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    print("\(#function)")
   guard let httpResponse = navigationResponse.response as? HTTPURLResponse else {
        decisionHandler(.allow)
        return
    }
    
    let policy : WKNavigationResponsePolicy = httpResponse.statusCode == 200 ? .allow : .cancel
    decisionHandler(policy)        
}

// 4) 网页加载成功 
func webView(_ webView: WKWebView,didFinish navigation: WKNavigation!) {
    print("\(#function)")
}

// 4) 加载失败
func webView(_ webView: WKWebView,didFail navigation: WKNavigation!,withError error: Error) {
    print("\(#function)")
   print(error.localizedDescription)
}

WKUIDelegate

主要讲讲网页js的一些函数——

  • alert()

  • comfirm()

  • prompt()

UIWebView中,js使用上述三个函数,是可以成功弹出的。但是在WKWebView中,使用着三个函数,是不会用任何反应的。原因是,把这三个函数都分别封装到WKUIDelegate方法中。但js使用这些函数时,那么客户端会在以下几个协议方法中,监测到发送过来的信息,然后需要用原生代码去实现一个alert。累cry~~~

// MARK: alert
func webView(_ webView: WKWebView,runJavaScriptAlertPanelWithMessage message: String,initiatedByFrame frame: WKFrameInfo,completionHandler: @escaping () -> Void) {
    let alert = UIAlertController(title: "这是本地代码弹窗",message: message,preferredStyle: .alert)
    lert.addAction(UIAlertAction(title: "ok",style: .cancel,handler: { _ in
            // 必须加入这个 肥调,不然会闪 (逃
        completionHandler()
  }))
    present(alert,animated: true,completion: nil)
}
    
// MARK: comfirm
func webView(_ webView: WKWebView,runJavaScriptConfirmPanelWithMessage message: String,completionHandler: @escaping (Bool) -> Void) {
    let alert = UIAlertController(title: "这是本地代码弹窗",preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "❤️",style: .default,handler: { _ in
        completionHandler(true)
    }))
    alert.addAction(UIAlertAction(title: "不❤️",handler: { _ in
        completionHandler(false)
    }))
    present(alert,completion: nil)
}
    
// MARK: prompt
func webView(_ webView: WKWebView,runJavaScriptTextInputPanelWithPrompt prompt: String,defaultText: String?,completionHandler: @escaping (String?) -> Void) {
    
    let alert = UIAlertController(title: "这是本地代码弹窗",message: prompt,preferredStyle: .alert)
    alert.addTextField { textField in
        textField.placeholder = defaultText
    }
    alert.addAction(UIAlertAction(title: "ok",handler: { _ in
        completionHandler(alert.textFields?.last?.text)
    }))
    present(alert,completion: nil)
    
}

踩坑

网页适配

有些网页在客户端上显示,会出现一些不适配的情况。使用UIWebView的话,我们可以用使用其的scaleToFit属性。即webView.scaleToFit = true。但是在WKWebView里,并没有这个属性,我们只能使用到JS注入进行修改

// 这句相当于给网页注入一个 <Meta> 标签,<Meta name="viewport" content="width=device-width">
let jsToScaleFit = "var Meta = document.createElement('Meta'); Meta.setAttribute('name','viewport'); Meta.setAttribute('content','width=device-width'); document.getElementsByTagName('head')[0].appendChild(Meta);"

let scaleToFitScript = WKUserScript(source: jsToScaleFit,injectionTime: .atDocumentEnd,forMainFrameOnly: true)
        
let userController = WKUserContentController()
userController.addUserScript(scaleToFitScript)
        
let config = WKWebViewConfiguration()
config.userContentController = userController
        
let wkWeb = WKWebView(frame: view.bounds,configuration: config!)

不过,还是不太推荐客户端去注入适配代码。最好还是告知前端,让他们去搞定这问题。个人觉得,两端少点干涉还是比较好滴~~~ (逃

客户端 -> 网页

有时间,我们需要客户端去调用前端的一些代码。e.g.

// 比如获取网页内容高度
let jsToGetWebHeight = "document.body.offsetHeight"

wkWeb?.evaluateJavaScript(jsToGetWebHeight,completionHandler: { (data,error) in
    print(error?.localizedDescription ?? "执行正确")
    // data 是一个 any 类型,因此需要做好类型判断
    if let webHeight : CGFloat = data as? CGFloat {
        print(webHeight)
    }
})

网页 -> 客户端

不像UIWebViewWKWebView无法使用JaveSciptCore。我们需要使用到WKScriptMessageHandler这个协议去进行一系列交互。

首先,在初始化阶段,需要使用到WKWebViewConfiguration。放个文档注释先。

/*! @abstract Adds a script message handler.
@param scriptMessageHandler The message handler to add.
@param name The name of the message handler.
@discussion Adding a scriptMessageHandler adds a function window.webkit.messageHandlers.<name>.postMessage(<messageBody>) for all frames. */

open func add(_ scriptMessageHandler: WKScriptMessageHandler,name: String)

name是客户端自定义好的一个字符串类型的命名空间。可以有多个name。网页的js代码,需要在进行交互的地方,使用上

window.webkit.messageHandlers.<name>.postMessage(<messageBody>)

来发送消息。

上个栗子 原文链接:https://www.f2er.com/swift/321367.html

猜你在找的Swift相关文章