// WKWebViewController.swift
// ProductionReport
import UIKit
import WebKit
class WKWebViewController: UIViewController {
// MARK: - lazy
fileprivate lazy var webView: WKWebView = { [unowned self] in
// 创建webveiew
// 创建一个webiview的配置项
let configuretion = WKWebViewConfiguration()
// Webview的偏好设置
configuretion.preferences = WKPreferences()
configuretion.preferences.minimumFontSize = 10
configuretion.preferences.javaScriptEnabled = true
// 默认是不能通过JS自动打开窗口的,必须通过用户交互才能打开
configuretion.preferences.javaScriptCanOpenWindowsAutomatically = false
// 通过js与webview内容交互配置
configuretion.userContentController = WKUserContentController()
// 添加一个JS到HTML中,这样就可以直接在JS中调用我们添加的JS方法
let js = "function showAlert() { alert('在载入webview时通过Swift注入的JS方法'); }"
let script = WKUserScript(source: js, injectionTime: .atDocumentStart,// 在载入时就添加JS
forMainFrameOnly: true) // 只添加到mainFrame中
configuretion.userContentController.addUserScript(script)
// 添加一个名称,就可以在JS通过这个名称发送消息:
// window.webkit.messageHandlers.AppModel.postMessage({body: 'xxx'})
configuretion.userContentController.add(self as WKScriptMessageHandler, name: "MingModel")
let webView = WKWebView(frame: self.view.bounds, configuration: configuretion)
webView.navigationDelegate = self
webView.uiDelegate = self
return webView
}()
fileprivate lazy var progressView: UIProgressView = {
let progressView = UIProgressView(progressViewStyle: .bar)
progressView.frame.size.width = self.view.frame.size.width
// 这里可以改进度条颜色
progressView.tintColor = UIColor.green
return progressView
}()
// MARK: - 生命周期
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
view.addSubview(webView)
view.insertSubview(progressView, aboveSubview: webView)
}
convenience init(navigationTitle: String, urlStr: String) {
self.init(nibName: nil, bundle: nil)
navigationItem.title = navigationTitle
webView.load(URLRequest(url: URL(string: urlStr)!))
}
convenience init(navigationTitle: String, url: URL) {
self.init(nibName: nil, bundle: nil)
navigationItem.title = navigationTitle
webView.load(URLRequest(url: url))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.edgesForExtendedLayout = UIRectEdge()
webView.addObserver(self, forKeyPath: "loading", options: .new, context: nil)
webView.addObserver(self, forKeyPath: "title", options: .new, context: nil)
webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "loading" {
// print("loading")
} else if keyPath == "title" {
title = self.webView.title
} else if keyPath == "estimatedProgress" {
print(webView.estimatedProgress)
progressView.setProgress(Float(webView.estimatedProgress), animated: true)
}
UIView.animate(withDuration: 0.5) {
self.progressView.isHidden = (self.progressView.progress == 1)
}
if webView.isLoading {
// 手动调用JS代码
let js = "callJsAlert()"
webView.evaluateJavaScript(js, completionHandler: { (any, err) in
debugPrint(any)
})
}
}
// 移除观察者
deinit {
webView.removeObserver(self, forKeyPath: "loading")
webView.removeObserver(self, forKeyPath: "title")
webView.removeObserver(self, forKeyPath: "estimatedProgress")
}
}
// MARK: - WKScriptMessageHandler
extension WKWebViewController: WKScriptMessageHandler {
// WKScriptMessageHandler:必须实现的函数,是APP与js交互,提供从网页中收消息的回调方法
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
print(message.webView)
}
}
// MARK: - WKNavigationDelegate
extension WKWebViewController: WKNavigationDelegate {
// 决定导航的动作,通常用于处理跨域的链接能否导航。WebKit对跨域进行了安全检查限制,不允许跨域,因此我们要对不能跨域的链接
// 单独处理。但是,对于Safari是允许跨域的,不用这么处理。
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
let hostname = (navigationAction.request as NSURLRequest).url?.host?.lowercased()
print(hostname)
print(navigationAction.navigationType)
// 处理跨域问题
if navigationAction.navigationType == .linkActivated && hostname!.contains(".baidu.com") {
// 手动跳转
UIApplication.shared.openURL(navigationAction.request.url!)
// 不允许导航
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print(#function)
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
print(#function)
decisionHandler(.allow)
}
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
print(#function)
completionHandler(.performDefaultHandling, nil)
}
}
// MARK: - WKUIDelegate
extension WKWebViewController: WKUIDelegate {
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
let alert = UIAlertController(title: "tip", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "ok", style: .default, handler: { (_) -> Void in
// We must call back js
completionHandler()
}))
self.present(alert, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
completionHandler(true)
}
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
completionHandler("woqu")
}
func webViewDidClose(_ webView: WKWebView) {
print("close")
}
}
WKWebView
// WebViewController.swift
// ProductionReport
import UIKit
// MARK: - Class: WebViewController
class WebViewController: UIViewController {
// MARK: - 属性
fileprivate var webView = UIWebView(frame: .zero)
fileprivate var urlStr: String?
fileprivate let loadProgressAnimationView: LoadProgressAnimationView = LoadProgressAnimationView(frame: CGRect(x: 0, y: 0, width: MGScreenW, height: 3))
// MARK: - 生命周期
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
view.addSubview(webView)
webView.addSubview(loadProgressAnimationView)
webView.scalesPageToFit = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(navigationTitle: String, urlStr: String) {
self.init(nibName: nil, bundle: nil)
navigationItem.title = navigationTitle
webView.loadRequest(URLRequest(url: URL(string: urlStr)!))
self.urlStr = urlStr
}
override func viewDidLoad() {
super.viewDidLoad()
view.frame = MGScreenBounds
automaticallyAdjustsScrollViewInsets = true
view.backgroundColor = UIColor.white
view.backgroundColor = UIColor.colorWithCustom(r: 230, g: 230, b: 230)
buildRightItemBarButton()
webView.frame = CGRect(x: 0, y: navHeight, width: MGScreenW, height: view.mg_height)
webView.backgroundColor = UIColor.colorWithCustom(r: 230, g: 230, b: 230)
webView.delegate = self
webView.dataDetectorTypes = .all // 设置某些数据变为链接形式,这个枚举可以设置如电话号,地址,邮箱等转化为链接
webView.mediaPlaybackAllowsAirPlay = true //设置音频播放是否支持ari play功能
webView.suppressesIncrementalRendering = true // 设置是否将数据加载如内存后渲染界面
webView.keyboardDisplayRequiresUserAction = true // 设置用户交互模式
// webView.paginationMode = .topToBottom // 这个属性用来设置一种模式,当网页的大小超出view时,将网页以翻页的效果展示
webView.scrollView.contentInset = UIEdgeInsets(top: -navHeight, left: 0, bottom: navHeight, right: 0)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
// MARK: - 导航栏
private func buildRightItemBarButton() {
let rightButton = UIButton(frame: CGRect(x: 0, y: 0, width: 60, height: 44))
rightButton.setImage(UIImage(named: "v2_refresh"), for: UIControlState.normal)
rightButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -53)
rightButton.addTarget(self, action: #selector(WebViewController.refreshClick), for: UIControlEvents.touchUpInside)
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightButton)
}
// MARK: - Action
func refreshClick() {
if urlStr != nil && urlStr!.characters.count > 1 {
webView.loadRequest(URLRequest(url: URL(string: urlStr!)!))
}
}
}
// MARK: - UIWebViewDelegate
extension WebViewController: UIWebViewDelegate {
func webViewDidStartLoad(_ webView: UIWebView) {
loadProgressAnimationView.startLoadProgressAnimation()
}
func webViewDidFinishLoad(_ webView: UIWebView) {
loadProgressAnimationView.endLoadProgressAnimation()
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
showHint(hint: "\(error)")
loadProgressAnimationView.endLoadProgressAnimation()
}
// func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
// let str = request.url?.absoluteString
// if (str?.hasPrefix("tel"))! {
// UIApplication.shared.openURL((URL(string: str!))!)
// }
// return true
// }
}
// MARK: -
// MARK: - Class: LoadProgressAnimationView
class LoadProgressAnimationView: UIView {
var viewWidth: CGFloat = 0
override var frame: CGRect {
willSet {
if frame.size.width == viewWidth {
self.isHidden = true
}
super.frame = frame
}
}
override init(frame: CGRect) {
super.init(frame: frame)
viewWidth = frame.size.width
backgroundColor = UIColor.randomColor()
self.frame.size.width = 0
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - 加载进度动画
func startLoadProgressAnimation() {
self.frame.size.width = 0
isHidden = false
UIView.animate(withDuration: 0.8, animations: { () -> Void in
self.frame.size.width = self.viewWidth * 0.70
}) { (finish) -> Void in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.08, execute: {
UIView.animate(withDuration: 0.3, animations: {
self.frame.size.width = self.viewWidth * 0.85
})
})
}
}
func endLoadProgressAnimation() {
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.frame.size.width = self.viewWidth*0.99
}) { (finish) -> Void in
self.isHidden = true
}
}
}
UIWebView.png
扫一扫,关注我.jpg
网友评论