Swift WKWebView

准备

添加权限

使得除了https的网站也能在iOS中运行起来
在这里插入图片描述

import

import WebKit

设置根视图

var webView: WKWebView!

override func loadView() {
    
    let config = WKWebViewConfiguration()
    
    webView = WKWebView(frame: .zero, configuration: config)
    webView.allowsBackForwardNavigationGestures = true
    webView.uiDelegate = self
    webView.navigationDelegate = self //就是LoadDelegate
    view = webView
}

override func viewDidLoad() {
    super.viewDidLoad()
    webView.load("https://www.google.com")
}

在另个WKWebView.swift里面

import UIKit
import WebKit

extension WKWebView {
    func load(_ string: String) {
        if let url = URL(string: string) {
            load(URLRequest(url: url))
        }
    }
}

一些方法

var webView: WKWebView!
//用于判断
webView.isLoading
webView.canGoBack
webView.canGoForward

//方法
webView.reload()
webView.reloadFromOrigin()
webView.stopLoading()
webView.goBack()
webView.goForward()

设置JS的三个弹出框为iOS原生alert

首先遵循协议

extension ViewController: WKUIDelegate {}

alert() 警告框

extension ViewController: WKUIDelegate {
	func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
	    let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
	    alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) in
	        completionHandler()
	    }))
	    present(alert, animated: true, completion: nil)
	}
}

confirm() 确认框

extension ViewController: WKUIDelegate {
	func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
	    let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
	    alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) in
	        completionHandler(false)
	    }))
	    alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) in
	        completionHandler(true)
	    }))
	    present(alert, animated: true, completion: nil)
	}
}

prompt() 输入框

extension ViewController: WKUIDelegate {
	func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
	    let alert = UIAlertController(title: nil, message: prompt, preferredStyle: .alert)
	    alert.addTextField { (textField) in
	        textField.placeholder = defaultText
	    }
	    alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) in
	        completionHandler(alert.textFields?.last?.text)
	    }))
	    present(alert, animated: true, completion: nil)
	}
}

添加小菊花

在这里插入图片描述

设置样式

var spinner: UIActivityIndicatorView!

func setSpinner() {
    spinner = UIActivityIndicatorView(style: .whiteLarge)
    spinner.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.8012895976)
    spinner.layer.cornerRadius = 10
    spinner.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(spinner)
    
    spinner.centerXAnchor.constraint(equalTo: webView.centerXAnchor).isActive = true
    spinner.centerYAnchor.constraint(equalTo: webView.centerYAnchor).isActive = true
    spinner.widthAnchor.constraint(equalToConstant: 80).isActive = true
    spinner.heightAnchor.constraint(equalToConstant: 80).isActive = true
}

小菊花的一生

spinner.startAnimating()
spinner.stopAnimating()
spinner.removeFromSuperview()

六个生命周期函数

遵循协议

extension ViewController: WKNavigationDelegate {}

请求之前

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    print(#function)
//        if let url = navigationAction.request.url {
//            if url.host != "www.google.com" {
//                UIApplication.shared.open(url)
//                decisionHandler(.cancel)
//                return
//            }
//        }
    decisionHandler(.allow)
}

开始加载

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    print(#function)
    spinner.startAnimating()
}

接收到网站的响应之后

一般都会跳转到一个页面显示错误的编号例如404,403

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    print(#function)
    if let httpResponse = navigationResponse.response as? HTTPURLResponse {
        if httpResponse.statusCode == 200 {
            decisionHandler(.allow)
        }else{
            let sb = UIStoryboard(name: "Main", bundle: Bundle.main)
            let vc = sb.instantiateViewController(identifier: "error") as! ErrorVC
            vc.errorStatus = httpResponse.statusCode
            vc.modalPresentationStyle = .fullScreen
            present(vc, animated: true, completion: nil)
            decisionHandler(.cancel)
        }
    }
}

开始从服务器中接收数据

func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
    print(#function)
}

结束接收

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    print(#function)
    spinner.stopAnimating()
    spinner.removeFromSuperview()
}

接收失败

func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
    print(#function)
    spinner.stopAnimating()
    spinner.removeFromSuperview()
}

注入HTML

一小段

baseURL用于说明加载资源文件的地址

func handleHTMLString() {
    let html = """
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
                <title>Text</title>
                </head>
        <body>
            <div style="text-align: center;font-size: 80px;margin-top: 350px">Text</div>
        </body>
    </html>
    """
    
    webView.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
}

.html文件

用deletingPathExtension是因为一般HTML的资源文件是和html文件放在同一个包里面

func handleHTMLFile() {
    let url = Bundle.main.url(forResource: "HomePage", withExtension: "html")!
    webView.loadFileURL(url, allowingReadAccessTo: url.deletingPathExtension())
}

注入JavaScript

以document.body.offsetHeight为例子

func handleJS() {
    webView.evaluateJavaScript("document.body.offsetHeight") { (res, error) in
        print(res)
    }
}

一般放在结束接收的函数里面

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    print(#function)
    spinner.stopAnimating()
    spinner.removeFromSuperview()
    handleJS()
}

加载进度条(KVO)

在这里插入图片描述

添加观察者

webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)

观察变化

//观察者观察的值一旦变化就会自动调用这个函数
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == #keyPath(WKWebView.estimatedProgress) {
        print(webView.estimatedProgress)
        //可在这里添加关于progressView的代码
        progerssView.progress = webView.estimatedProgress
    }
}

销毁观察者

因为观察者的存在非常消耗内存
一般都在class ViewController里面的deinit销毁

deinit {
    webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress))
}

和Web前段进行数据交互

Web的和iOS交互的函数

假设要传一个user
就必须得用window.webkit.messageHandlers.name.postMessage(messageBody)

<script type="text/javascript">
    function sendMessageToIOS() {
        var user = {
            name: "zjh"
            age: 20
        };
        window.webkit.messageHandlers.name.postMessage(user)
    }
</script>

设置self来处理数据

let config = WKWebViewConfiguration()
//name是在js代码中识别的
config.userContentController.add(self, name: "key")

遵循协议完成取数据的方法

extension ViewController: WKScriptMessageHandler{
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "key" {
            print(message.body)
        }
    }
}

截取WebView

config.rect用来设置截取的大小然后放到with变量后面,若截取的是整个webView则用nil

func takeSnapShot() {
    let config = WKSnapshotConfiguration()
    config.rect = CGRect(x: 0, y: 0, width: 200, height: 200)
    webView.takeSnapshot(with: config) { (image, error) in
        guard let image = image else {return}
        print(image.size)
    }
}

处理Cookie

读取和删除cookie

func handleCookie() {
    webView.configuration.websiteDataStore.httpCookieStore.getAllCookies({ cookies in
        for cookie in cookies {
            if cookie.name == "auth" {
                self.webView.configuration.websiteDataStore.httpCookieStore.delete(cookie)
            }else{
                print(cookie.value)
            }
        }
    })
}
发布了19 篇原创文章 · 获赞 8 · 访问量 1444

猜你喜欢

转载自blog.csdn.net/qq_44864362/article/details/104188036