文章目录
准备
添加权限
使得除了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)
}
}
})
}